libdict
Data Structure C Library
Loading...
Searching...
No Matches
pr_tree.c
Go to the documentation of this file.
1/*
2 * libdict -- internal path reduction 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/*
29 * cf. [Gonnet 1983], [Gonnet 1984]
30 */
31
32#include "pr_tree.h"
33
34#include "dict_private.h"
35#include "tree_common.h"
36
37typedef struct pr_node pr_node;
38struct pr_node {
40 unsigned weight;
41};
42
43#define WEIGHT(n) ((n) ? (n)->weight : 1)
44
48
52
53static const dict_vtable pr_tree_vtable = {
54 true,
69};
70
71static const itor_vtable pr_tree_itor_vtable = {
90};
91
92static unsigned fixup(pr_tree* tree, pr_node* node);
93static void rot_left(pr_tree* tree, pr_node* node);
94static void rot_right(pr_tree* tree, pr_node* node);
95static pr_node* node_new(void* key);
96
99{
100 ASSERT(cmp_func != NULL);
101
102 pr_tree* tree = MALLOC(sizeof(*tree));
103 if (tree) {
104 tree->root = NULL;
105 tree->count = 0;
106 tree->cmp_func = cmp_func;
107 tree->rotation_count = 0;
108 }
109 return tree;
110}
111
112dict*
114{
115 dict* dct = MALLOC(sizeof(*dct));
116 if (dct) {
117 if (!(dct->_object = pr_tree_new(cmp_func))) {
118 FREE(dct);
119 return NULL;
120 }
121 dct->_vtable = &pr_tree_vtable;
122 }
123 return dct;
124}
125
126size_t pr_tree_free(pr_tree* tree, dict_delete_func delete_func) { return tree_free(tree, delete_func); }
127void** pr_tree_search(pr_tree* tree, const void* key) { return tree_search(tree, key); }
128void** pr_tree_search_le(pr_tree* tree, const void* key) { return tree_search_le(tree, key); }
129void** pr_tree_search_lt(pr_tree* tree, const void* key) { return tree_search_lt(tree, key); }
130void** pr_tree_search_ge(pr_tree* tree, const void* key) { return tree_search_ge(tree, key); }
131void** pr_tree_search_gt(pr_tree* tree, const void* key) { return tree_search_gt(tree, key); }
132
133static unsigned
134fixup(pr_tree* tree, pr_node* node)
135{
136 /*
137 * The internal path length of a tree is defined as the sum of levels of
138 * all the tree's internal nodes. Path-reduction trees are similar to
139 * weight-balanced trees, except that rotations are only made when they can
140 * reduce the total internal path length of the tree. These particular
141 * trees are in the class BB[1/3], but because of these restrictions their
142 * performance is superior to BB[1/3] trees.
143 *
144 * Consider a node N.
145 * A single left rotation is performed when
146 * WEIGHT(n->llink) < WEIGHT(n->rlink->rlink)
147 * A right-left rotation is performed when
148 * WEIGHT(n->llink) < WEIGHT(n->rlink->llink)
149 *
150 * A single right rotation is performed when
151 * WEIGHT(n->rlink) > WEIGHT(n->llink->llink)
152 * A left-right rotation is performed when
153 * WEIGHT(n->rlink) > WEIGHT(n->llink->rlink)
154 *
155 * Although the worst case number of rotations for a single insertion or
156 * deletion is O(n), the amortized worst-case number of rotations is
157 * .44042lg(n) + O(1) for insertion, and .42062lg(n) + O(1) for deletion.
158 *
159 * We use tail recursion to minimize the number of recursive calls. For
160 * single rotations, no recursive call is made, and we tail recurse to
161 * continue checking for out-of-balance conditions. For double, we make one
162 * recursive call and then tail recurse.
163 */
164 unsigned rotations = 0;
165 const unsigned lweight = WEIGHT(node->llink);
166 const unsigned rweight = WEIGHT(node->rlink);
167 if (lweight < rweight) {
168 pr_node* r = node->rlink;
169 ASSERT(r != NULL);
170 if (WEIGHT(r->rlink) > lweight) { /* LL */
171 rot_left(tree, node);
172 rotations += 1;
173 rotations += fixup(tree, node);
174 /* Commenting the next line means we must make the weight
175 * verification condition in node_verify() less stringent. */
176 rotations += fixup(tree, r);
177 } else if (WEIGHT(r->llink) > lweight) { /* RL */
178 /* Rotate |r| right, then |node| left, with |rl| taking the place
179 * of |node| and having |node| and |r| as left and right children,
180 * respectively. */
181 pr_node* const rl = r->llink;
182 pr_node* const parent = node->parent;
183
184 pr_node* const a = rl->llink;
185 rl->llink = node;
186 node->parent = rl;
187 if ((node->rlink = a) != NULL)
188 a->parent = node;
189
190 pr_node* const b = rl->rlink;
191 rl->rlink = r;
192 r->parent = rl;
193 if ((r->llink = b) != NULL)
194 b->parent = r;
195
196 rl->parent = parent;
197 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = rl;
198
199 node->weight += WEIGHT(a) - r->weight;
200 r->weight += WEIGHT(b) - rl->weight;
201 rl->weight = node->weight + r->weight;
202
203 rotations += 1;
204 rotations += fixup(tree, r);
205 rotations += fixup(tree, node);
206 }
207 } else if (lweight > rweight) {
208 pr_node* l = node->llink;
209 ASSERT(l != NULL);
210 if (WEIGHT(l->llink) > rweight) { /* RR */
211 rot_right(tree, node);
212 rotations += 1;
213 rotations += fixup(tree, node);
214 /* Commenting the next line means we must turn the weight
215 * verification condition in node_verify() less stringent. */
216 rotations += fixup(tree, l);
217 } else if (WEIGHT(l->rlink) > rweight) { /* LR */
218 /* Rotate |l| left, then |node| right, with |lr| taking the place of
219 * |node| and having |l| and |node| as left and right children,
220 * respectively. */
221 pr_node* const lr = l->rlink;
222 pr_node* const parent = node->parent;
223
224 pr_node* const a = lr->llink;
225 lr->llink = l;
226 l->parent = lr;
227 if ((l->rlink = a) != NULL)
228 a->parent = l;
229
230 pr_node* const b = lr->rlink;
231 lr->rlink = node;
232 node->parent = lr;
233 if ((node->llink = b) != NULL)
234 b->parent = node;
235
236 lr->parent = parent;
237 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = lr;
238
239 node->weight += WEIGHT(b) - l->weight;
240 l->weight += WEIGHT(a) - lr->weight;
241 lr->weight = node->weight + l->weight;
242
243 rotations += 2;
244 rotations += fixup(tree, l);
245 rotations += fixup(tree, node);
246 }
247 }
248 return rotations;
249}
250
253{
254 int cmp = 0;
255 pr_node* node = tree->root;
256 pr_node* parent = NULL;
257 while (node) {
258 cmp = tree->cmp_func(key, node->key);
259 if (cmp < 0) {
260 parent = node; node = node->llink;
261 } else if (cmp > 0) {
262 parent = node; node = node->rlink;
263 } else
264 return (dict_insert_result) { &node->datum, false };
265 }
266
267 pr_node* add = node_new(key);
268 if (!add)
269 return (dict_insert_result) { NULL, false };
270 if (!(add->parent = parent)) {
271 ASSERT(tree->count == 0);
272 ASSERT(tree->root == NULL);
273 tree->root = add;
274 } else {
275 if (cmp < 0)
276 parent->llink = add;
277 else
278 parent->rlink = add;
279
280 unsigned rotations = 0;
281 while ((node = parent) != NULL) {
282 parent = parent->parent;
283 ++node->weight;
284 rotations += fixup(tree, node);
285 }
286 tree->rotation_count += rotations;
287 }
288 tree->count++;
289 return (dict_insert_result) { &add->datum, true };
290}
291
292static void
293remove_node(pr_tree* tree, pr_node* node)
294{
295 if (node->llink && node->rlink) {
296 pr_node* out;
297 if (node->llink->weight > node->rlink->weight) {
298 out = tree_node_max(node->llink);
299 } else {
300 out = tree_node_min(node->rlink);
301 }
302 void* tmp;
303 SWAP(node->key, out->key, tmp);
304 SWAP(node->datum, out->datum, tmp);
305 node = out;
306 }
307 ASSERT(!node->llink || !node->rlink);
308 /* Splice in the successor, if any. */
309 pr_node* child = node->llink ? node->llink : node->rlink;
310 pr_node* parent = node->parent;
311 if (child)
312 child->parent = parent;
313 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = child;
314 FREE(node);
315 tree->count--;
316 /* Now move up the tree, decrementing weights. */
317 unsigned rotations = 0;
318 while (parent) {
319 --parent->weight;
320 pr_node* up = parent->parent;
321 rotations += fixup(tree, parent);
322 parent = up;
323 }
324 tree->rotation_count += rotations;
325}
326
328pr_tree_remove(pr_tree* tree, const void* key)
329{
330 pr_node* node = tree_search_node(tree, key);
331 if (!node)
332 return (dict_remove_result) { NULL, NULL, false };
333 dict_remove_result result = { node->key, node->datum, true };
334 remove_node(tree, node);
335 return result;
336}
337
338size_t pr_tree_clear(pr_tree* tree, dict_delete_func delete_func) { return tree_clear(tree, delete_func); }
339
340size_t
342{
343 return tree_traverse(tree, visit, user_data);
344}
345
346bool
347pr_tree_select(pr_tree* tree, size_t n, const void** key, void** datum)
348{
349 if (n >= tree->count) {
350 if (key)
351 *key = NULL;
352 if (datum)
353 *datum = NULL;
354 return false;
355 }
356 pr_node* node = tree->root;
357 for (;;) {
358 const unsigned nw = WEIGHT(node->llink);
359 if (n + 1 >= nw) {
360 if (n + 1 == nw) {
361 if (key)
362 *key = node->key;
363 if (datum)
364 *datum = node->datum;
365 return true;
366 }
367 n -= nw;
368 node = node->rlink;
369 } else {
370 node = node->llink;
371 }
372 }
373}
374
375size_t pr_tree_count(const pr_tree* tree) { return tree_count(tree); }
379
380static pr_node*
381node_new(void* key)
382{
383 pr_node* node = MALLOC(sizeof(*node));
384 if (node) {
385 node->key = key;
386 node->datum = NULL;
387 node->parent = NULL;
388 node->llink = NULL;
389 node->rlink = NULL;
390 node->weight = 2;
391 }
392 return node;
393}
394
395/*
396 * rot_left(T, B):
397 *
398 * / /
399 * B D
400 * / \ / \
401 * A D ==> B E
402 * / \ / \
403 * C E A C
404 *
405 * Only the weights of B and B's right child to be readjusted.
406 */
407static void
408rot_left(pr_tree* tree, pr_node *node)
409{
410 ASSERT(node->rlink != NULL);
411
412 pr_node* rlink = node->rlink;
414
415 node->weight = WEIGHT(node->llink) + WEIGHT(node->rlink);
416 rlink->weight = node->weight + WEIGHT(rlink->rlink);
417}
418
419/*
420 * rot_right(T, D):
421 *
422 * / /
423 * D B
424 * / \ / \
425 * B E ==> A D
426 * / \ / \
427 * A C C E
428 *
429 * Only the weights of D and D's left child need to be readjusted.
430 */
431static void
432rot_right(pr_tree* tree, pr_node* node)
433{
434 ASSERT(node->llink != NULL);
435
436 pr_node* llink = node->llink;
438
439 node->weight = WEIGHT(node->llink) + WEIGHT(node->rlink);
440 llink->weight = WEIGHT(llink->llink) + node->weight;
441}
442
443static bool
444node_verify(const pr_tree* tree, const pr_node* parent, const pr_node* node)
445{
446 if (!parent) {
447 VERIFY(tree->root == node);
448 } else {
449 VERIFY(parent->llink == node || parent->rlink == node);
450 }
451 if (node) {
452 VERIFY(node->parent == parent);
453 if (parent) {
454 if (parent->llink == node) {
455 VERIFY(tree->cmp_func(parent->key, node->key) > 0);
456 } else {
457 ASSERT(parent->rlink == node);
458 VERIFY(tree->cmp_func(parent->key, node->key) < 0);
459 }
460 }
461 pr_node* l = node->llink;
462 pr_node* r = node->rlink;
463 if (!node_verify(tree, node, l) ||
464 !node_verify(tree, node, r))
465 return false;
466 unsigned lweight = WEIGHT(l);
467 unsigned rweight = WEIGHT(r);
468 VERIFY(node->weight == lweight + rweight);
469 if (r && rweight > lweight) {
470 VERIFY(WEIGHT(r->rlink) <= lweight);
471 VERIFY(WEIGHT(r->llink) <= lweight);
472 } else if (l && lweight > rweight) {
473 VERIFY(WEIGHT(l->llink) <= rweight);
474 VERIFY(WEIGHT(l->rlink) <= rweight);
475 }
476 }
477 return true;
478}
479
480bool
482{
483 if (tree->root) {
484 VERIFY(tree->count > 0);
485 } else {
486 VERIFY(tree->count == 0);
487 }
488 return node_verify(tree, NULL, tree->root);
489}
490
491pr_itor*
493{
494 pr_itor* itor = MALLOC(sizeof(*itor));
495 if (itor) {
496 itor->tree = tree;
497 itor->node = NULL;
498 }
499 return itor;
500}
501
504{
505 dict_itor* itor = MALLOC(sizeof(*itor));
506 if (itor) {
507 if (!(itor->_itor = pr_itor_new(tree))) {
508 FREE(itor);
509 return NULL;
510 }
511 itor->_vtable = &pr_tree_itor_vtable;
512 }
513 return itor;
514}
515
517bool pr_itor_valid(const pr_itor* itor) { return tree_iterator_valid(itor); }
519bool pr_itor_next(pr_itor* itor) { return tree_iterator_next(itor); }
520bool pr_itor_prev(pr_itor* itor) { return tree_iterator_prev(itor); }
521bool pr_itor_nextn(pr_itor* itor, size_t count) { return tree_iterator_nextn(itor, count); } /* TODO: speed up */
522bool pr_itor_prevn(pr_itor* itor, size_t count) { return tree_iterator_prevn(itor, count); } /* TODO: speed up */
523bool pr_itor_first(pr_itor* itor) { return tree_iterator_first(itor); }
524bool pr_itor_last(pr_itor* itor) { return tree_iterator_last(itor); }
525bool pr_itor_search(pr_itor* itor, const void* key) { return tree_iterator_search(itor, key); }
526bool pr_itor_search_le(pr_itor* itor, const void* key) { return tree_iterator_search_le(itor, key); }
527bool pr_itor_search_lt(pr_itor* itor, const void* key) { return tree_iterator_search_lt(itor, key); }
528bool pr_itor_search_ge(pr_itor* itor, const void* key) { return tree_iterator_search_ge(itor, key); }
529bool pr_itor_search_gt(pr_itor* itor, const void* key) { return tree_iterator_search_gt(itor, key); }
530const void* pr_itor_key(const pr_itor* itor) { return tree_iterator_key(itor); }
531void** pr_itor_datum(pr_itor* itor) { return tree_iterator_datum(itor); }
532int pr_itor_compare(const pr_itor* i1, const pr_itor* i2) { return tree_iterator_compare(i1, i2); }
533
534bool
536{
537 if (!it->node)
538 return false;
539 remove_node(it->tree, it->node);
540 it->node = NULL;
541 return true;
542}
dict_remove_result(* dict_remove_func)(void *obj, const void *key)
Definition dict.h:90
int(* dict_compare_func)(const void *, const void *)
Definition dict.h:54
bool(* dict_select_func)(void *obj, size_t n, const void **key, void **datum)
Definition dict.h:93
void(* dict_invalidate_func)(void *itor)
Definition dict.h:117
size_t(* dict_traverse_func)(void *obj, dict_visit_func visit, void *user_data)
Definition dict.h:92
dict_insert_result(* dict_insert_func)(void *obj, void *key)
Definition dict.h:87
void(* dict_delete_func)(void *, void *)
Definition dict.h:57
int(* dict_icompare_func)(void *itor1, void *itor2)
Definition dict.h:128
bool(* dict_nextn_func)(void *itor, size_t count)
Definition dict.h:120
bool(* dict_valid_func)(const void *itor)
Definition dict.h:116
size_t(* dict_count_func)(const void *obj)
Definition dict.h:94
bool(* dict_first_func)(void *itor)
Definition dict.h:122
bool(* dict_next_func)(void *itor)
Definition dict.h:118
void *(* dict_key_func)(void *itor)
Definition dict.h:124
size_t(* dict_dfree_func)(void *obj, dict_delete_func delete_func)
Definition dict.h:85
void **(* dict_datum_func)(void *itor)
Definition dict.h:125
bool(* dict_prevn_func)(void *itor, size_t count)
Definition dict.h:121
void **(* dict_search_func)(void *obj, const void *key)
Definition dict.h:88
bool(* dict_isearch_func)(void *itor, const void *key)
Definition dict.h:126
bool(* dict_iremove_func)(void *itor)
Definition dict.h:127
bool(* dict_prev_func)(void *itor)
Definition dict.h:119
dict_itor *(* dict_inew_func)(void *obj)
Definition dict.h:84
bool(* dict_last_func)(void *itor)
Definition dict.h:123
bool(* dict_verify_func)(const void *obj)
Definition dict.h:95
bool(* dict_visit_func)(const void *, void *, void *)
Definition dict.h:59
size_t(* dict_clear_func)(void *obj, dict_delete_func delete_func)
Definition dict.h:91
void(* dict_ifree_func)(void *itor)
Definition dict.h:115
#define FREE(p)
#define ASSERT(expr)
#define VERIFY(expr)
#define MALLOC(n)
#define SWAP(a, b, v)
pr_tree * pr_tree_new(dict_compare_func cmp_func)
Definition pr_tree.c:98
size_t pr_tree_max_path_length(const pr_tree *tree)
Definition pr_tree.c:376
dict * pr_dict_new(dict_compare_func cmp_func)
Definition pr_tree.c:113
void ** pr_tree_search_gt(pr_tree *tree, const void *key)
Definition pr_tree.c:131
void ** pr_tree_search_lt(pr_tree *tree, const void *key)
Definition pr_tree.c:129
const void * pr_itor_key(const pr_itor *itor)
Definition pr_tree.c:530
bool pr_itor_next(pr_itor *itor)
Definition pr_tree.c:519
dict_itor * pr_dict_itor_new(pr_tree *tree)
Definition pr_tree.c:503
dict_insert_result pr_tree_insert(pr_tree *tree, void *key)
Definition pr_tree.c:252
size_t pr_tree_traverse(pr_tree *tree, dict_visit_func visit, void *user_data)
Definition pr_tree.c:341
bool pr_itor_prevn(pr_itor *itor, size_t count)
Definition pr_tree.c:522
bool pr_itor_remove(pr_itor *it)
Definition pr_tree.c:535
bool pr_itor_nextn(pr_itor *itor, size_t count)
Definition pr_tree.c:521
dict_remove_result pr_tree_remove(pr_tree *tree, const void *key)
Definition pr_tree.c:328
void pr_itor_free(pr_itor *itor)
Definition pr_tree.c:516
bool pr_itor_valid(const pr_itor *itor)
Definition pr_tree.c:517
void ** pr_tree_search_ge(pr_tree *tree, const void *key)
Definition pr_tree.c:130
int pr_itor_compare(const pr_itor *i1, const pr_itor *i2)
Definition pr_tree.c:532
bool pr_itor_prev(pr_itor *itor)
Definition pr_tree.c:520
bool pr_tree_select(pr_tree *tree, size_t n, const void **key, void **datum)
Definition pr_tree.c:347
size_t pr_tree_min_path_length(const pr_tree *tree)
Definition pr_tree.c:377
bool pr_itor_last(pr_itor *itor)
Definition pr_tree.c:524
size_t pr_tree_clear(pr_tree *tree, dict_delete_func delete_func)
Definition pr_tree.c:338
bool pr_itor_search_le(pr_itor *itor, const void *key)
Definition pr_tree.c:526
bool pr_itor_search_ge(pr_itor *itor, const void *key)
Definition pr_tree.c:528
size_t pr_tree_free(pr_tree *tree, dict_delete_func delete_func)
Definition pr_tree.c:126
bool pr_itor_search(pr_itor *itor, const void *key)
Definition pr_tree.c:525
bool pr_itor_first(pr_itor *itor)
Definition pr_tree.c:523
#define WEIGHT(n)
Definition pr_tree.c:43
void ** pr_tree_search_le(pr_tree *tree, const void *key)
Definition pr_tree.c:128
void ** pr_itor_datum(pr_itor *itor)
Definition pr_tree.c:531
size_t pr_tree_total_path_length(const pr_tree *tree)
Definition pr_tree.c:378
size_t pr_tree_count(const pr_tree *tree)
Definition pr_tree.c:375
bool pr_tree_verify(const pr_tree *tree)
Definition pr_tree.c:481
pr_itor * pr_itor_new(pr_tree *tree)
Definition pr_tree.c:492
void pr_itor_invalidate(pr_itor *itor)
Definition pr_tree.c:518
void ** pr_tree_search(pr_tree *tree, const void *key)
Definition pr_tree.c:127
bool pr_itor_search_gt(pr_itor *itor, const void *key)
Definition pr_tree.c:529
bool pr_itor_search_lt(pr_itor *itor, const void *key)
Definition pr_tree.c:527
void * _itor
Definition dict.h:175
const itor_vtable * _vtable
Definition dict.h:176
Definition dict.h:151
void * _object
Definition dict.h:152
const dict_vtable * _vtable
Definition dict.h:153
pr_tree * tree
Definition pr_tree.c:50
pr_node * node
Definition pr_tree.c:50
pr_node * llink
Definition pr_tree.c:39
void * datum
Definition pr_tree.c:39
unsigned weight
Definition pr_tree.c:40
pr_node * rlink
Definition pr_tree.c:39
void * key
Definition pr_tree.c:39
pr_node * parent
Definition pr_tree.c:39
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)
size_t tree_free(void *Tree, dict_delete_func delete_func)
void ** tree_iterator_datum(void *Iterator)
bool tree_iterator_next(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_node_rot_left(void *Tree, void *Node)
Definition tree_common.c:46
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)
size_t tree_clear(void *Tree, dict_delete_func delete_func)
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)
bool tree_iterator_nextn(void *Iterator, size_t count)
size_t tree_traverse(void *Tree, dict_visit_func visit, void *user_data)
size_t tree_total_path_length(const void *Tree)
bool tree_iterator_first(void *Iterator)
void tree_iterator_free(void *Iterator)
bool tree_iterator_prevn(void *Iterator, size_t count)
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)
bool tree_iterator_search_gt(void *Iterator, const void *key)
void ** tree_search_ge(void *Tree, const void *key)
void tree_node_rot_right(void *Tree, void *Node)
Definition tree_common.c:62
void ** tree_search_le(void *Tree, const void *key)
bool tree_iterator_search(void *Iterator, const void *key)
bool tree_iterator_prev(void *Iterator)
#define TREE_NODE_FIELDS(node_type)
Definition tree_common.h:33
#define TREE_ITERATOR_FIELDS(tree_type, node_type)
Definition tree_common.h:54
#define TREE_FIELDS(node_type)
Definition tree_common.h:44