libdict 1.0.7
Data Structure C Library
Loading...
Searching...
No Matches
hb_tree.c
Go to the documentation of this file.
1/*
2 * libdict -- height-balanced (AVL) tree implementation.
3 *
4 * Copyright (c) 2001-2014, Farooq Mela
5 * All rights reserved.
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 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "hb_tree.h"
29
30#include "dict_private.h"
31#include "tree_common.h"
32
33typedef struct hb_node hb_node;
34
35struct hb_node {
36 void* key;
37 void* datum;
38 union {
39 intptr_t bal;
41 };
44};
45
46#define BAL_MASK ((intptr_t)3)
47#define PARENT(node) ((hb_node*) ((node)->bal & ~BAL_MASK))
48#define BAL_POS(node) ((node)->bal & 1)
49#define BAL_NEG(node) ((node)->bal & 2)
50
51/* hb_node is handed to the generic routines in tree_common.c as though it were
52 * a tree_node_base, so its first five members must sit at the same offsets.
53 * The third of those, the parent pointer, additionally carries the balance
54 * factor in its two low bits, so ONLY this file's PARENT() macro may decode
55 * it: any tree_common routine that reads |parent| directly (tree_traverse,
56 * tree_select, tree_clear, tree_iterator_next/prev, tree_node_rot_*) would
57 * dereference a tagged, misaligned pointer and must be reimplemented here. */
58_Static_assert(sizeof(intptr_t) == sizeof(hb_node*),
59 "hb_node tags a parent pointer stored in an intptr_t");
60_Static_assert(offsetof(hb_node, key) == offsetof(tree_node_base, key),
61 "hb_node must be layout-compatible with tree_node_base");
62_Static_assert(offsetof(hb_node, datum) == offsetof(tree_node_base, datum),
63 "hb_node must be layout-compatible with tree_node_base");
64_Static_assert(offsetof(hb_node, bal) == offsetof(tree_node_base, parent),
65 "hb_node must be layout-compatible with tree_node_base");
66_Static_assert(offsetof(hb_node, llink) == offsetof(tree_node_base, llink),
67 "hb_node must be layout-compatible with tree_node_base");
68_Static_assert(offsetof(hb_node, rlink) == offsetof(tree_node_base, rlink),
69 "hb_node must be layout-compatible with tree_node_base");
70
74
78
79/* Vtable thunks. The vtable slot types take void*, and calling a function
80 * through a function-pointer type that is not compatible with the function's
81 * own type is undefined behaviour (C11 6.5.2.2p9), so each slot below gets a
82 * thunk with the exact slot signature instead of a cast. A cast would also
83 * hide a genuine signature mismatch. */
84static dict_itor* vt_hb_dict_itor_new(void* obj) { return hb_dict_itor_new(obj); }
85static size_t vt_hb_tree_free(void* obj, dict_delete_func delete_func) { return hb_tree_free(obj, delete_func); }
86static dict_insert_result vt_hb_tree_insert(void* obj, void* key) { return hb_tree_insert(obj, key); }
87static dict_remove_result vt_hb_tree_remove(void* obj, const void* key) { return hb_tree_remove(obj, key); }
88static size_t vt_hb_tree_clear(void* obj, dict_delete_func delete_func) { return hb_tree_clear(obj, delete_func); }
89static size_t vt_hb_tree_traverse(void* obj, dict_visit_func visit, void* user_data) { return hb_tree_traverse(obj, visit, user_data); }
90static bool vt_hb_tree_select(void* obj, size_t n, const void** key, void** datum) { return hb_tree_select(obj, n, key, datum); }
91static bool vt_hb_tree_verify(const void* obj) { return hb_tree_verify(obj); }
92static bool vt_hb_itor_next(void* itor) { return hb_itor_next(itor); }
93static bool vt_hb_itor_prev(void* itor) { return hb_itor_prev(itor); }
94static bool vt_hb_itor_nextn(void* itor, size_t count) { return hb_itor_nextn(itor, count); }
95static bool vt_hb_itor_prevn(void* itor, size_t count) { return hb_itor_prevn(itor, count); }
96static bool vt_hb_itor_remove(void* itor) { return hb_itor_remove(itor); }
97
98static const dict_vtable hb_tree_vtable = {
99 true,
100 vt_hb_dict_itor_new,
101 vt_hb_tree_free,
102 vt_hb_tree_insert,
108 vt_hb_tree_remove,
109 vt_hb_tree_clear,
110 vt_hb_tree_traverse,
111 vt_hb_tree_select,
113 vt_hb_tree_verify,
114};
115
116static const itor_vtable hb_tree_itor_vtable = {
120 vt_hb_itor_next,
121 vt_hb_itor_prev,
122 vt_hb_itor_nextn,
123 vt_hb_itor_prevn,
133 vt_hb_itor_remove,
135};
136
137static hb_node* node_prev(hb_node* node);
138static hb_node* node_next(hb_node* node);
139static hb_node* node_new(void* key);
140
141static bool node_verify(const hb_tree* tree, const hb_node* parent, const hb_node* node,
142 unsigned* height, size_t *count,
143 const void* lower, const void* upper);
144
145hb_tree*
147{
148 ASSERT(cmp_func != NULL);
149
150 hb_tree* tree = MALLOC(sizeof(*tree));
151 if (tree) {
152 tree->root = NULL;
153 tree->count = 0;
154 tree->cmp_func = cmp_func;
155 tree->rotation_count = 0;
156 }
157 return tree;
158}
159
160dict*
162{
163 dict* dct = MALLOC(sizeof(*dct));
164 if (dct) {
165 if (!(dct->_object = hb_tree_new(cmp_func))) {
166 FREE(dct);
167 return NULL;
168 }
169 dct->_vtable = &hb_tree_vtable;
170 }
171 return dct;
172}
173
174size_t
176 const size_t count = hb_tree_clear(tree, delete_func);
177 FREE(tree);
178 return count;
179}
180
181size_t
183{
184 const size_t count = tree->count;
185
186 hb_node* node = tree->root;
187 while (node) {
188 if (node->llink || node->rlink) {
189 node = node->llink ? node->llink : node->rlink;
190 continue;
191 }
192 if (delete_func) delete_func(node->key, node->datum);
193 hb_node* const parent = PARENT(node);
194 /* Unlink before freeing: comparing a pointer to a freed object is UB. */
195 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = NULL;
196 FREE(node);
197 node = parent;
198 }
199 ASSERT(tree->root == NULL);
200 tree->count = 0;
201 return count;
202}
203
204/* L: rotate |q| left */
205static bool
206rotate_l(hb_tree* restrict const tree, hb_node* restrict const q)
207{
208 hb_node* restrict const qp = PARENT(q);
209 hb_node* restrict const qr = q->rlink;
210
211 ASSERT(BAL_POS(q));
212
213 hb_node *restrict const qrl = qr->llink;
214 const int qr_bal = qr->bal & BAL_MASK;
215
216 /* q->parent <- qr; q->bal <- (qr_bal == 0); */
217 q->bal = (intptr_t)qr | (qr_bal == 0);
218 if ((q->rlink = qrl) != NULL)
219 qrl->bal = (intptr_t)q | (qrl->bal & BAL_MASK); /* qrl->parent <- q; */
220
221 /* qr->parent <- qp; qr->bal <- -(qr_bal == 0); */
222 qr->bal = (intptr_t)qp | ((qr_bal == 0) << 1);
223 qr->llink = q;
224 *(qp == NULL ? &tree->root : qp->llink == q ? &qp->llink : &qp->rlink) = qr;
225
226 return (qr_bal == 0);
227}
228
229/* R: rotate |q| right. */
230static bool
231rotate_r(hb_tree* restrict const tree, hb_node* restrict const q)
232{
233 hb_node* restrict const qp = PARENT(q);
234 hb_node* restrict const ql = q->llink;
235
236 ASSERT(BAL_NEG(q));
237
238 hb_node* restrict const qlr = ql->rlink;
239 const int ql_bal = ql->bal & BAL_MASK;
240
241 /* q->parent <- ql; q->bal <- -(ql_bal == 0); */
242 q->bal = (intptr_t)ql | ((ql_bal == 0) << 1);
243 if ((q->llink = qlr) != NULL)
244 qlr->bal = (intptr_t)q | (qlr->bal & BAL_MASK); /* qlr->parent <- q; */
245
246 /* ql->parent <- qp; ql->bal <- (ql_bal == 0); */
247 ql->bal = (intptr_t)qp | (ql_bal == 0);
248 ql->rlink = q;
249 *(qp == NULL ? &tree->root : qp->llink == q ? &qp->llink : &qp->rlink) = ql;
250
251 return (ql_bal == 0);
252}
253
254/* RL: Rotate |q->rlink| right, then |q| left. */
255static void
256rotate_rl(hb_tree* restrict const tree, hb_node* restrict const q)
257{
258 hb_node* restrict const qp = PARENT(q);
259 hb_node* restrict const qr = q->rlink;
260 hb_node* restrict const qrl = qr->llink;
261
262 ASSERT(BAL_POS(q));
263 ASSERT(BAL_NEG(qr));
264
265 const int qrl_bal = qrl->bal & BAL_MASK;
266 hb_node* restrict const qrll = qrl->llink;
267 hb_node* restrict const qrlr = qrl->rlink;
268
269 /* qrl->parent <- qp; qrl->bal <- 0; */
270 qrl->bal = (intptr_t)qp;
271 *(qp == NULL ? &tree->root : qp->llink == q ? &qp->llink : &qp->rlink) = qrl;
272 qrl->llink = q;
273 qrl->rlink = qr;
274
275 /* q->parent <- qrl; q->bal <- -(qrl_bal == 1); */
276 q->bal = (intptr_t)qrl | ((qrl_bal == 1) << 1);
277 if ((q->rlink = qrll) != NULL)
278 qrll->bal = (intptr_t)q | (qrll->bal & BAL_MASK);
279
280 /* qr->parent <- qrl; qr->bal <- (qrl_bal == -1); */
281 qr->bal = (intptr_t)qrl | (qrl_bal == 2);
282 if ((qr->llink = qrlr) != NULL)
283 qrlr->bal = (intptr_t)qr | (qrlr->bal & BAL_MASK);
284}
285
286/* LR: rotate |q->llink| left, then rotate |q| right. */
287static void
288rotate_lr(hb_tree* restrict const tree, hb_node* restrict const q)
289{
290 hb_node* restrict const qp = PARENT(q);
291 hb_node* restrict const ql = q->llink;
292 hb_node* restrict const qlr = ql->rlink;
293
294 ASSERT(BAL_NEG(q));
295 ASSERT(BAL_POS(ql));
296
297 const int qlr_bal = qlr->bal & BAL_MASK;
298 hb_node* restrict const qlrl = qlr->llink;
299 hb_node* restrict const qlrr = qlr->rlink;
300
301 /* qlr->parent <- qp; qlr->bal <- 0; */
302 qlr->bal = (intptr_t)qp;
303 *(qp == NULL ? &tree->root : qp->llink == q ? &qp->llink : &qp->rlink) = qlr;
304 qlr->llink = ql;
305 qlr->rlink = q;
306
307 /* q->parent <- qlr; q->bal = (qlr_bal == -1); */
308 q->bal = (intptr_t)qlr | (qlr_bal == 2);
309 if ((q->llink = qlrr) != NULL)
310 qlrr->bal = (intptr_t)q | (qlrr->bal & BAL_MASK);
311
312 /* ql->parent <- qlr; ql->bal <- -(qlr_bal == 1); */
313 ql->bal = (intptr_t)qlr | ((qlr_bal == 1) << 1);
314 if ((ql->rlink = qlrl) != NULL)
315 qlrl->bal = (intptr_t)ql | (qlrl->bal & BAL_MASK);
316}
317
320{
321 int cmp = 0;
322 hb_node* node = tree->root;
323 hb_node* parent = NULL;
324 hb_node* q = NULL;
325
326 while (node) {
327 cmp = tree->cmp_func(key, node->key);
328 if (cmp < 0) {
329 parent = node; node = node->llink;
330 } else if (cmp > 0) {
331 parent = node; node = node->rlink;
332 } else
333 return (dict_insert_result) { &node->datum, false };
334 if (parent->bal & BAL_MASK)
335 q = parent;
336 }
337
338 hb_node* const add = node = node_new(key);
339 if (!node)
340 return (dict_insert_result) { NULL, false };
341
342 if (!(node->pptr = parent)) {
343 ASSERT(tree->count == 0);
344 ASSERT(tree->root == NULL);
345 tree->root = node;
346 } else {
347 if (cmp < 0)
348 parent->llink = node;
349 else
350 parent->rlink = node;
351
352 while (parent != q) {
353 ASSERT((parent->bal & BAL_MASK) == 0);
354 if (parent->llink == node)
355 parent->bal |= 2;
356 else
357 parent->bal |= 1;
358 node = parent;
359 parent = PARENT(parent);
360 }
361 if (q) {
362 ASSERT(q->bal & BAL_MASK);
363 if (q->llink == node) {
364 if (BAL_NEG(q)) { /* if q->balance == -1 */
365 if (BAL_POS(q->llink)) { /* if q->llink->balance == +1 */
366 tree->rotation_count += 2;
367 rotate_lr(tree, q);
368 } else {
369 tree->rotation_count += 1;
370 ASSERT(!rotate_r(tree, q));
371 }
372 } else { /* else, q->balance == +1 */
373 ASSERT(BAL_POS(q));
374 q->bal &= ~BAL_MASK; /* q->balance <- 0 */
375 }
376 } else {
377 ASSERT(q->rlink == node);
378 if (BAL_POS(q)) { /* if q->balance == +1 */
379 if (BAL_NEG(q->rlink)) { /* if q->rlink->balance == -1 */
380 tree->rotation_count += 2;
381 rotate_rl(tree, q);
382 } else {
383 tree->rotation_count += 1;
384 ASSERT(!rotate_l(tree, q));
385 }
386 } else { /* else, q->balance == -1 */
387 ASSERT(BAL_NEG(q));
388 q->bal &= ~BAL_MASK; /* q->balance <- 0 */
389 }
390 }
391 }
392 }
393 tree->count++;
394 return (dict_insert_result) { &add->datum, true };
395}
396
397void** hb_tree_search(hb_tree* tree, const void* key) { return tree_search(tree, key); }
398void** hb_tree_search_le(hb_tree* tree, const void* key) { return tree_search_le(tree, key); }
399void** hb_tree_search_lt(hb_tree* tree, const void* key) { return tree_search_lt(tree, key); }
400void** hb_tree_search_ge(hb_tree* tree, const void* key) { return tree_search_ge(tree, key); }
401void** hb_tree_search_gt(hb_tree* tree, const void* key) { return tree_search_gt(tree, key); }
402
403static void
404remove_node(hb_tree* tree, hb_node* node)
405{
406 if (node->llink && node->rlink) {
407 hb_node* restrict out =
408 BAL_POS(node) ? tree_node_min(node->rlink) : tree_node_max(node->llink);
409 void* tmp;
410 SWAP(node->key, out->key, tmp);
411 SWAP(node->datum, out->datum, tmp);
412 node = out;
413 }
414
415 hb_node* p = PARENT(node);
416 hb_node* child = node->llink ? node->llink : node->rlink;
417 /* Decide which side of |p| the node hangs off BEFORE freeing it:
418 * comparing a pointer to a freed object is UB. */
419 bool left = p && (p->llink == node);
420 ASSERT(!p || left || p->rlink == node);
421 FREE(node);
422 tree->count--;
423 if (child)
424 child->bal = (intptr_t)p | (child->bal & BAL_MASK);
425 if (!p) {
426 tree->root = child;
427 return;
428 }
429
430 if (left) {
431 p->llink = child;
432 } else {
433 p->rlink = child;
434 }
435 node = child;
436
437 unsigned rotations = 0;
438 for (;;) {
439 if (left) {
440 ASSERT(p->llink == node);
441 if (BAL_POS(p)) { /* if p->balance == +1 */
442 if (BAL_NEG(p->rlink)) { /* if p->rlink->balance == -1 */
443 rotations += 2;
444 rotate_rl(tree, p);
445 } else {
446 rotations += 1;
447 if (rotate_l(tree, p)) break;
448 }
449 node = PARENT(p);
450 } else if (BAL_NEG(p)) { /* else if p->balance == -1 */
451 p->bal &= ~BAL_MASK; /* p->balance <- 0 */
452 node = p;
453 } else { /* else, p->balance == 0 */
454 ASSERT((p->bal & BAL_MASK) == 0);
455 p->bal |= 1; /* p->balance <- +1 */
456 break;
457 }
458 } else {
459 ASSERT(p->rlink == node);
460 if (BAL_NEG(p)) { /* if p->balance == -1 */
461 if (BAL_POS(p->llink)) { /* if p->llink->balance == +1 */
462 rotations += 2;
463 rotate_lr(tree, p);
464 } else {
465 rotations += 1;
466 if (rotate_r(tree, p))
467 break;
468 }
469 node = PARENT(p);
470 } else if (BAL_POS(p)) { /* else if p->balance == +1 */
471 p->bal &= ~BAL_MASK; /* p->balance <- 0 */
472 node = p;
473 } else { /* else, p->balance == 0 */
474 ASSERT((p->bal & BAL_MASK) == 0);
475 p->bal |= 2; /* p->balance <- -1 */
476 break;
477 }
478 }
479
480 if (!(p = PARENT(node)))
481 break;
482 if (p->llink == node) {
483 left = true;
484 } else {
485 ASSERT(p->rlink == node);
486 left = false;
487 }
488 }
489 tree->rotation_count += rotations;
490}
491
493hb_tree_remove(hb_tree* tree, const void* key)
494{
495 hb_node* node = tree_search_node(tree, key);
496 if (!node)
497 return (dict_remove_result) { NULL, NULL, false };
498 const dict_remove_result result = { node->key, node->datum, true };
499 remove_node(tree, node);
500 return result;
501}
502
503size_t
505{
506 ASSERT(visit != NULL);
507
508 /* NOTE: this must NOT delegate to the generic tree_traverse(). hb_node
509 * packs the balance factor into the low bits of its parent pointer, so
510 * only node_next()/PARENT() may walk the parent chain here. */
511 size_t count = 0;
512 for (hb_node* node = tree_node_min(tree->root); node; node = node_next(node)) {
513 ++count;
514 if (!visit(node->key, node->datum, user_data))
515 break;
516 }
517 return count;
518}
519
520bool
521hb_tree_select(hb_tree *tree, size_t n, const void **key, void **datum)
522{
523 if (n >= tree->count) {
524 if (key)
525 *key = NULL;
526 if (datum)
527 *datum = NULL;
528 return false;
529 }
530 hb_node* node;
531 if (n >= tree->count / 2) {
532 node = tree_node_max(tree->root);
533 n = tree->count - 1 - n;
534 while (n--)
535 node = node_prev(node);
536 } else {
537 node = tree_node_min(tree->root);
538 while (n--)
539 node = node_next(node);
540 }
541 if (key)
542 *key = node->key;
543 if (datum)
544 *datum = node->datum;
545 return true;
546}
547
548size_t hb_tree_count(const hb_tree* tree) { return tree_count(tree); }
552
553static hb_node*
554node_new(void* key)
555{
556 hb_node* node = MALLOC(sizeof(*node));
557 if (node) {
558 /* The two low bits of the parent pointer hold the balance factor, so
559 * a node must be at least 4-byte aligned. dict_malloc_func is
560 * user-replaceable, and an ASSERT would vanish under NDEBUG and let a
561 * misaligned allocator corrupt every parent pointer silently. */
562 if ((((uintptr_t) node) & 3) != 0) {
563 fprintf(stderr, "%s:%d (%s) dict_malloc_func returned a pointer "
564 "that is not 4-byte aligned: %p\n",
565 __FILE__, __LINE__, __func__, (void*) node);
566 abort();
567 }
568 node->key = key;
569 node->datum = NULL;
570 node->bal = 0; /* also initializes parent to NULL */
571 node->llink = NULL;
572 node->rlink = NULL;
573 }
574 return node;
575}
576
577static hb_node*
578node_prev(hb_node* node)
579{
580 if (node->llink)
581 return tree_node_max(node->llink);
582 hb_node* parent = PARENT(node);
583 while (parent && parent->llink == node) {
584 node = parent;
585 parent = PARENT(parent);
586 }
587 return parent;
588}
589
590static hb_node*
591node_next(hb_node* node)
592{
593 if (node->rlink)
594 return tree_node_min(node->rlink);
595 hb_node* parent = PARENT(node);
596 while (parent && parent->rlink == node) {
597 node = parent;
598 parent = PARENT(parent);
599 }
600 return parent;
601}
602
603static bool
604node_verify(const hb_tree* tree, const hb_node* parent, const hb_node* node,
605 unsigned* height, size_t *count, const void* lower, const void* upper)
606{
607 if (!parent) {
608 VERIFY(tree->root == node);
609 } else {
610 /* Was an ASSERT, which vanishes under NDEBUG and then silently
611 * accepted a node whose claimed parent had no link back to it. */
612 VERIFY(parent->llink == node || parent->rlink == node);
613 }
614 if (node) {
615 /* Global BST ordering. Comparing a node only against its immediate
616 * parent would accept an entire subtree placed on the wrong side:
617 * root 5, 5->llink 3, 3->rlink 7 passes every parent-local check yet
618 * makes key 7 unreachable from the root. */
619 if (lower)
620 VERIFY(tree->cmp_func(lower, node->key) < 0);
621 if (upper)
622 VERIFY(tree->cmp_func(upper, node->key) > 0);
623
624 int bal = node->bal & BAL_MASK;
625 VERIFY(bal >= 0);
626 VERIFY(bal <= 2);
627 if (bal == 2) {
628 VERIFY(node->llink != NULL);
629 bal = -1;
630 } else if (bal == 1) {
631 VERIFY(node->rlink != NULL);
632 }
633 VERIFY(PARENT(node) == parent);
634 unsigned lheight, rheight;
635 if (!node_verify(tree, node, node->llink, &lheight, count, lower, node->key) ||
636 !node_verify(tree, node, node->rlink, &rheight, count, node->key, upper))
637 return false;
638 VERIFY(bal == (int)rheight - (int)lheight);
639 if (height)
640 *height = MAX(lheight, rheight) + 1;
641 *count += 1;
642 } else {
643 if (height)
644 *height = 0;
645 }
646 return true;
647}
648
649bool
651{
652 size_t count = 0;
653 /* Only check the tally if the structure itself verified: otherwise
654 * node_verify() bailed out with a partial count and the count mismatch
655 * would mask the real failure it already reported. */
656 if (!node_verify(tree, NULL, tree->root, NULL, &count, NULL, NULL))
657 return false;
658 VERIFY(tree->count == count);
659 return true;
660}
661
662hb_itor*
664{
665 hb_itor* itor = MALLOC(sizeof(*itor));
666 if (itor) {
667 itor->tree = tree;
668 itor->node = NULL;
669 }
670 return itor;
671}
672
675{
676 dict_itor* itor = MALLOC(sizeof(*itor));
677 if (itor) {
678 if (!(itor->_itor = hb_itor_new(tree))) {
679 FREE(itor);
680 return NULL;
681 }
682 itor->_vtable = &hb_tree_itor_vtable;
683 }
684 return itor;
685}
686
688bool hb_itor_valid(const hb_itor* itor) { return tree_iterator_valid(itor); }
690
692 if (itor->node)
693 itor->node = node_next(itor->node);
694 return itor->node != NULL;
695}
696
698 if (itor->node)
699 itor->node = node_prev(itor->node);
700 return itor->node != NULL;
701}
702
703bool hb_itor_nextn(hb_itor* itor, size_t count) {
704 while (itor->node && count--)
705 itor->node = node_next(itor->node);
706 return itor->node != NULL;
707}
708
709bool hb_itor_prevn(hb_itor* itor, size_t count) {
710 while (itor->node && count--)
711 itor->node = node_prev(itor->node);
712 return itor->node != NULL;
713}
714
715bool hb_itor_first(hb_itor* itor) { return tree_iterator_first(itor); }
716bool hb_itor_last(hb_itor* itor) { return tree_iterator_last(itor); }
717bool hb_itor_search(hb_itor* itor, const void* key) { return tree_iterator_search(itor, key); }
718bool hb_itor_search_le(hb_itor* itor, const void* key) { return tree_iterator_search_le(itor, key); }
719bool hb_itor_search_lt(hb_itor* itor, const void* key) { return tree_iterator_search_lt(itor, key); }
720bool hb_itor_search_ge(hb_itor* itor, const void* key) { return tree_iterator_search_ge(itor, key); }
721bool hb_itor_search_gt(hb_itor* itor, const void* key) { return tree_iterator_search_gt(itor, key); }
722int hb_itor_compare(const hb_itor* i1, const hb_itor* i2) { return tree_iterator_compare(i1, i2); }
723const void* hb_itor_key(const hb_itor* itor) { return tree_iterator_key(itor); }
724void** hb_itor_datum(hb_itor* itor) { return tree_iterator_datum(itor); }
725
726bool
728{
729 if (!itor->node)
730 return false;
731 remove_node(itor->tree, itor->node);
732 itor->node = NULL;
733 return true;
734}
int(* dict_compare_func)(const void *, const void *)
A pointer to a function that compares two keys.
Definition dict.h:59
void(* dict_delete_func)(void *, void *)
A pointer to a function that is called when a key-value pair gets removed from a dictionary.
Definition dict.h:62
bool(* dict_visit_func)(const void *, void *, void *)
A pointer to a function used for iterating over dictionary contents.
Definition dict.h:64
#define FREE(p)
#define ASSERT(expr)
#define VERIFY(expr)
#define MALLOC(n)
#define SWAP(a, b, v)
#define MAX(a, b)
bool hb_itor_search(hb_itor *itor, const void *key)
Position |itor| on |key| and return true, or unposition it and return false if |key| is not present.
Definition hb_tree.c:717
dict_itor * hb_dict_itor_new(hb_tree *tree)
Like hb_itor_new(), but wrapped in a generic dict_itor for use with the dict_itor_* macros.
Definition hb_tree.c:674
size_t hb_tree_clear(hb_tree *tree, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL.
Definition hb_tree.c:182
#define BAL_POS(node)
Definition hb_tree.c:48
bool hb_itor_search_gt(hb_itor *itor, const void *key)
Position |itor| on the least key greater than |key| and return true, or unposition it and return fals...
Definition hb_tree.c:721
void ** hb_tree_search_lt(hb_tree *tree, const void *key)
Return the address of the datum of the greatest key less than |key|, or NULL if there is none.
Definition hb_tree.c:399
#define PARENT(node)
Definition hb_tree.c:47
void ** hb_tree_search(hb_tree *tree, const void *key)
Return the address of the datum stored for |key|, or NULL if |key| is not present.
Definition hb_tree.c:397
#define BAL_NEG(node)
Definition hb_tree.c:49
bool hb_tree_select(hb_tree *tree, size_t n, const void **key, void **datum)
Store the key and datum of the |n|th element in key order (0-based) through |key| and |datum| and ret...
Definition hb_tree.c:521
dict * hb_dict_new(dict_compare_func cmp_func)
Like hb_tree_new(), but wrapped in a generic dict for use with the dict_* macros.
Definition hb_tree.c:161
bool hb_itor_search_ge(hb_itor *itor, const void *key)
Position |itor| on the least key greater than or equal to |key| and return true, or unposition it and...
Definition hb_tree.c:720
void hb_itor_free(hb_itor *itor)
Free an iterator.
Definition hb_tree.c:687
hb_itor * hb_itor_new(hb_tree *tree)
Create an iterator over |tree| that is not positioned on any element yet.
Definition hb_tree.c:663
bool hb_itor_search_lt(hb_itor *itor, const void *key)
Position |itor| on the greatest key less than |key| and return true, or unposition it and return fals...
Definition hb_tree.c:719
bool hb_itor_prev(hb_itor *itor)
Move |itor| to the previous element in key order and return true, or unposition it and return false i...
Definition hb_tree.c:697
void ** hb_tree_search_gt(hb_tree *tree, const void *key)
Return the address of the datum of the least key greater than |key|, or NULL if there is none.
Definition hb_tree.c:401
hb_tree * hb_tree_new(dict_compare_func cmp_func)
Create an empty tree that orders keys with |cmp_func| (must not be NULL).
Definition hb_tree.c:146
void hb_itor_invalidate(hb_itor *itor)
Unposition |itor|, so that it is not positioned on any element.
Definition hb_tree.c:689
size_t hb_tree_count(const hb_tree *tree)
Return the number of elements.
Definition hb_tree.c:548
bool hb_itor_valid(const hb_itor *itor)
Return whether |itor| is positioned on an element.
Definition hb_tree.c:688
size_t hb_tree_min_path_length(const hb_tree *tree)
Return the shallowest depth at which a child link is absent, the root being at depth 1,...
Definition hb_tree.c:549
dict_insert_result hb_tree_insert(hb_tree *tree, void *key)
Insert |key| unless an equal key is present.
Definition hb_tree.c:319
void ** hb_tree_search_ge(hb_tree *tree, const void *key)
Return the address of the datum of the least key greater than or equal to |key|, or NULL if there is ...
Definition hb_tree.c:400
bool hb_itor_nextn(hb_itor *itor, size_t count)
Move |itor| |count| elements forward and return whether it is still positioned.
Definition hb_tree.c:703
#define BAL_MASK
Definition hb_tree.c:46
bool hb_itor_remove(hb_itor *itor)
Remove the element |itor| is positioned on and unposition |itor|; return false if it was not position...
Definition hb_tree.c:727
size_t hb_tree_free(hb_tree *tree, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL,...
Definition hb_tree.c:175
dict_remove_result hb_tree_remove(hb_tree *tree, const void *key)
Remove the element with key |key|.
Definition hb_tree.c:493
size_t hb_tree_max_path_length(const hb_tree *tree)
Return the greatest depth of any node, the root being at depth 1, or 0 for an empty tree: the height ...
Definition hb_tree.c:550
int hb_itor_compare(const hb_itor *i1, const hb_itor *i2)
Compare the positions of two iterators over the same tree: return a negative value,...
Definition hb_tree.c:722
bool hb_itor_last(hb_itor *itor)
Position |itor| on the last element in key order and return true, or unposition it and return false i...
Definition hb_tree.c:716
bool hb_itor_prevn(hb_itor *itor, size_t count)
Move |itor| |count| elements back and return whether it is still positioned.
Definition hb_tree.c:709
void ** hb_itor_datum(hb_itor *itor)
Return the address of the datum |itor| is positioned on, through which it can be read or replaced,...
Definition hb_tree.c:724
bool hb_itor_next(hb_itor *itor)
Move |itor| to the next element in key order and return true, or unposition it and return false if th...
Definition hb_tree.c:691
const void * hb_itor_key(const hb_itor *itor)
Return the key |itor| is positioned on, or NULL if it is not positioned.
Definition hb_tree.c:723
bool hb_itor_search_le(hb_itor *itor, const void *key)
Position |itor| on the greatest key less than or equal to |key| and return true, or unposition it and...
Definition hb_tree.c:718
bool hb_tree_verify(const hb_tree *tree)
Check the internal invariants of the tree and return true if they hold, or print the first failed che...
Definition hb_tree.c:650
bool hb_itor_first(hb_itor *itor)
Position |itor| on the first element in key order and return true, or unposition it and return false ...
Definition hb_tree.c:715
size_t hb_tree_traverse(hb_tree *tree, dict_visit_func visit, void *user_data)
Call |visit|(key, datum, |user_data|) for each element in key order, stopping early if |visit| return...
Definition hb_tree.c:504
void ** hb_tree_search_le(hb_tree *tree, const void *key)
Return the address of the datum of the greatest key less than or equal to |key|, or NULL if there is ...
Definition hb_tree.c:398
size_t hb_tree_total_path_length(const hb_tree *tree)
Return the sum of the depths of all nodes, the root being at depth 1, or 0 for an empty tree.
Definition hb_tree.c:551
Height-balanced (AVL) tree.
void * _itor
Definition dict.h:235
const itor_vtable * _vtable
Definition dict.h:236
The operations of one container type.
Definition dict.h:110
Definition dict.h:164
void * _object
Definition dict.h:165
const dict_vtable * _vtable
Definition dict.h:166
hb_tree * tree
Definition hb_tree.c:76
hb_node * node
Definition hb_tree.c:76
hb_node * llink
Definition hb_tree.c:42
void * datum
Definition hb_tree.c:37
hb_node * pptr
Definition hb_tree.c:40
void * key
Definition hb_tree.c:36
hb_node * rlink
Definition hb_tree.c:43
intptr_t bal
Definition hb_tree.c:39
struct tree_node * rlink
Definition tree_common.c:34
struct tree_node * llink
Definition tree_common.c:34
dict_compare_func cmp_func
Definition tree_common.c:38
tree_node * root
Definition tree_common.c:38
size_t count
Definition tree_common.c:38
size_t rotation_count
Definition tree_common.c:38
bool tree_iterator_last(void *Iterator)
void ** tree_iterator_datum(void *Iterator)
void * tree_node_max(void *Node)
void tree_iterator_invalidate(void *Iterator)
void ** tree_search_gt(void *Tree, const void *key)
int tree_iterator_compare(const void *Iterator1, const void *Iterator2)
void * tree_search_node(void *Tree, const void *key)
bool tree_iterator_search_le(void *Iterator, const void *key)
bool tree_iterator_valid(const void *Iterator)
size_t tree_count(const void *Tree)
void ** tree_search_lt(void *Tree, const void *key)
const void * tree_iterator_key(const void *Iterator)
size_t tree_min_path_length(const void *Tree)
void * tree_node_min(void *Node)
void ** tree_search(void *Tree, const void *key)
size_t tree_total_path_length(const void *Tree)
bool tree_iterator_first(void *Iterator)
void tree_iterator_free(void *Iterator)
bool tree_iterator_search_lt(void *Iterator, const void *key)
bool tree_iterator_search_ge(void *Iterator, const void *key)
size_t tree_max_path_length(const void *Tree)
void * tree_iterator_key_vt(void *Iterator)
int tree_iterator_compare_vt(void *Iterator1, void *Iterator2)
bool tree_iterator_search_gt(void *Iterator, const void *key)
void ** tree_search_ge(void *Tree, const void *key)
void ** tree_search_le(void *Tree, const void *key)
bool tree_iterator_search(void *Iterator, const void *key)
#define TREE_ITERATOR_FIELDS(tree_type, node_type)
Definition tree_common.h:54
#define TREE_FIELDS(node_type)
Definition tree_common.h:44