libdict
Data Structure C Library
Loading...
Searching...
No Matches
wb_tree.c
Go to the documentation of this file.
1/*
2 * libdict -- weight-balanced 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 1984], [Nievergelt and Reingold 1973]
30 */
31
32#include "wb_tree.h"
33
34#include <limits.h>
35#include "dict_private.h"
36#include "tree_common.h"
37
38/* A tree BB[alpha] is said to be of weighted balance alpha if every node in
39 * the tree has a balance p(n) such that alpha <= p(n) <= 1 - alpha. The
40 * balance of a node is defined as the number of nodes in its left subtree
41 * divided by the number of nodes in either subtree. The weight of a node is
42 * defined as the number of external nodes in its subtrees.
43 *
44 * Legal values for alpha are 0 <= alpha <= 1/2. BB[0] is a normal, unbalanced
45 * binary tree, and BB[1/2] includes only completely balanced binary search
46 * trees of 2^height - 1 nodes. A higher value of alpha specifies a more
47 * stringent balance requirement.
48 *
49 * Values for alpha in the range 2/11 <= alpha <= 1 - sqrt(2)/2 are interesting
50 * because a tree can be brought back into weighted balance after an insertion or
51 * deletion using at most one rotation per level (thus the number of rotations
52 * after insertion or deletion is O(lg N)).
53 *
54 * These are the parameters for alpha = 1 - sqrt(2)/2 == .292893, as
55 * recommended in [Gonnet 1984]. */
56
57/* These constants are approximated by integer fractions in the code to
58 * eliminate floating point arithmetic. */
59#if 0
60# define ALPHA_0 .292893f /* 1 - sqrt(2)/2 */
61# define ALPHA_1 .707106f /* sqrt(2)/2 */
62# define ALPHA_2 .414213f /* sqrt(2) - 1 */
63# define ALPHA_3 .585786f /* 2 - sqrt(2) */
64#endif
65
66typedef struct wb_node wb_node;
67struct wb_node {
69 uint32_t weight;
70};
71
72#define WEIGHT(n) ((n) ? (n)->weight : 1U)
73
77
81
82static const dict_vtable wb_tree_vtable = {
83 true,
98};
99
100static const itor_vtable wb_tree_itor_vtable = {
119};
120
121static wb_node* node_new(void* key);
122
123wb_tree*
125{
126 ASSERT(cmp_func != NULL);
127
128 wb_tree* tree = MALLOC(sizeof(*tree));
129 if (tree) {
130 tree->root = NULL;
131 tree->count = 0;
132 tree->cmp_func = cmp_func;
133 tree->rotation_count = 0;
134 }
135 return tree;
136}
137
138dict*
140{
141 dict* dct = MALLOC(sizeof(*dct));
142 if (dct) {
143 if (!(dct->_object = wb_tree_new(cmp_func))) {
144 FREE(dct);
145 return NULL;
146 }
147 dct->_vtable = &wb_tree_vtable;
148 }
149 return dct;
150}
151
152void** wb_tree_search(wb_tree* tree, const void* key) { return tree_search(tree, key); }
153void** wb_tree_search_le(wb_tree* tree, const void* key) { return tree_search_le(tree, key); }
154void** wb_tree_search_lt(wb_tree* tree, const void* key) { return tree_search_lt(tree, key); }
155void** wb_tree_search_ge(wb_tree* tree, const void* key) { return tree_search_ge(tree, key); }
156void** wb_tree_search_gt(wb_tree* tree, const void* key) { return tree_search_gt(tree, key); }
157
158static inline unsigned
159fixup(wb_tree* tree, wb_node* n)
160{
161 unsigned rotations = 0;
162 unsigned weight = WEIGHT(n->llink);
163 if (weight * 1000U < n->weight * 293U) {
164 wb_node* nr = n->rlink;
165 ASSERT(nr != NULL);
166 wb_node* nrl = nr->llink;
167 if (WEIGHT(nrl) * 1000U < nr->weight * 586U) { /* LL */
168 /* Rotate |n| left. */
170 nr->weight = (n->weight = WEIGHT(n->llink) + WEIGHT(n->rlink)) +
171 WEIGHT(nr->rlink);
172 rotations += 1;
173 } else { /* RL */
174 /* Rotate |nr| right, then |n| left. */
175 ASSERT(nrl != NULL);
176 wb_node* const p = n->parent;
177 nrl->parent = p;
178 *(p ? (p->llink == n ? &p->llink : &p->rlink) : &tree->root) = nrl;
179
180 wb_node* const a = nrl->llink;
181 nrl->llink = n;
182 n->parent = nrl;
183 if ((n->rlink = a) != NULL)
184 a->parent = n;
185
186 wb_node* const b = nrl->rlink;
187 nrl->rlink = nr;
188 nr->parent = nrl;
189 if ((nr->llink = b) != NULL)
190 b->parent = nr;
191
192 nrl->weight = (n->weight = WEIGHT(n->llink) + WEIGHT(a)) +
193 (nr->weight = WEIGHT(b) + WEIGHT(nr->rlink));
194 rotations += 2;
195 }
196 } else if (weight * 1000U > n->weight * 707U) {
197 wb_node* nl = n->llink;
198 ASSERT(nl != NULL);
199 weight = WEIGHT(nl->llink);
200 if (weight * 1000U > nl->weight * 414U) { /* RR */
202
203 n->weight = WEIGHT(n->llink) + WEIGHT(n->rlink);
204 nl->weight = weight + n->weight;
205 rotations += 1;
206 } else { /* LR */
207 /* Rotate |nl| left, then |n| right. */
208 wb_node* nlr = nl->rlink;
209 ASSERT(nlr != NULL);
210 wb_node* const p = n->parent;
211 nlr->parent = p;
212 *(p ? (p->llink == n ? &p->llink : &p->rlink) : &tree->root) = nlr;
213
214 wb_node* const a = nlr->llink;
215 nlr->llink = nl;
216 nl->parent = nlr;
217 if ((nl->rlink = a) != NULL)
218 a->parent = nl;
219
220 wb_node* const b = nlr->rlink;
221 nlr->rlink = n;
222 n->parent = nlr;
223 if ((n->llink = b) != NULL)
224 b->parent = n;
225
226 nlr->weight = (n->weight = WEIGHT(b) + WEIGHT(n->rlink)) +
227 (nl->weight = WEIGHT(nl->llink) + WEIGHT(a));
228 rotations += 2;
229 }
230 }
231 return rotations;
232}
233
236{
237 int cmp = 0;
238
239 wb_node* node = tree->root;
240 wb_node* parent = NULL;
241 while (node) {
242 cmp = tree->cmp_func(key, node->key);
243 if (cmp < 0) {
244 parent = node; node = node->llink;
245 } else if (cmp) {
246 parent = node; node = node->rlink;
247 } else
248 return (dict_insert_result) { &node->datum, false };
249 }
250
251 wb_node* const add = node = node_new(key);
252 if (!add)
253 return (dict_insert_result) { NULL, false };
254
255 if (!(node->parent = parent)) {
256 ASSERT(tree->count == 0);
257 ASSERT(tree->root == NULL);
258 tree->root = node;
259 } else {
260 if (cmp < 0)
261 parent->llink = node;
262 else
263 parent->rlink = node;
264
265 unsigned rotations = 0;
266 while ((node = parent) != NULL) {
267 parent = node->parent;
268 ++node->weight;
269 rotations += fixup(tree, node);
270 }
271 tree->rotation_count += rotations;
272 }
273 tree->count++;
274 return (dict_insert_result) { &add->datum, true };
275}
276
277static void
278remove_node(wb_tree* tree, wb_node* node)
279{
280 if (node->llink && node->rlink) {
281 wb_node* out;
282 if (node->llink->weight > node->rlink->weight) {
283 out = tree_node_max(node->llink);
284 } else {
285 out = tree_node_min(node->rlink);
286 }
287 void* tmp;
288 SWAP(node->key, out->key, tmp);
289 SWAP(node->datum, out->datum, tmp);
290 node = out;
291 }
292 ASSERT(!node->llink || !node->rlink);
293 /* Splice in the successor, if any. */
294 wb_node* child = node->llink ? node->llink : node->rlink;
295 wb_node* parent = node->parent;
296 if (child)
297 child->parent = parent;
298 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = child;
299 FREE(node);
300 tree->count--;
301 /* Now move up the tree, decrementing weights. */
302 unsigned rotations = 0;
303 while (parent) {
304 --parent->weight;
305 wb_node* up = parent->parent;
306 rotations += fixup(tree, parent);
307 parent = up;
308 }
309 tree->rotation_count += rotations;
310}
311
313wb_tree_remove(wb_tree* tree, const void* key)
314{
315 wb_node* node = tree_search_node(tree, key);
316 if (!node)
317 return (dict_remove_result) { NULL, NULL, false };
318 dict_remove_result result = { node->key, node->datum, true };
319 remove_node(tree, node);
320 return result;
321}
322
323size_t wb_tree_free(wb_tree* tree, dict_delete_func delete_func) { return tree_free(tree, delete_func); }
324size_t wb_tree_clear(wb_tree* tree, dict_delete_func delete_func) { return tree_clear(tree, delete_func); }
325size_t wb_tree_traverse(wb_tree* tree, dict_visit_func visit, void* user_data) { return tree_traverse(tree, visit, user_data); }
326
327bool
328wb_tree_select(wb_tree* tree, size_t n, const void** key, void** datum)
329{
330 if (n >= tree->count) {
331 if (key)
332 *key = NULL;
333 if (datum)
334 *datum = NULL;
335 return false;
336 }
337 wb_node* node = tree->root;
338 for (;;) {
339 const unsigned nw = WEIGHT(node->llink);
340 if (n + 1 >= nw) {
341 if (n + 1 == nw) {
342 if (key)
343 *key = node->key;
344 if (datum)
345 *datum = node->datum;
346 return true;
347 }
348 n -= nw;
349 node = node->rlink;
350 } else {
351 node = node->llink;
352 }
353 }
354}
355
356size_t wb_tree_count(const wb_tree* tree) { return tree_count(tree); }
360
361static wb_node*
362node_new(void* key)
363{
364 wb_node* node = MALLOC(sizeof(*node));
365 if (node) {
366 node->key = key;
367 node->datum = NULL;
368 node->parent = NULL;
369 node->llink = NULL;
370 node->rlink = NULL;
371 node->weight = 2;
372 }
373 return node;
374}
375
376static bool
377node_verify(const wb_tree* tree, const wb_node* parent, const wb_node* node,
378 unsigned *weight)
379{
380 if (!parent) {
381 VERIFY(tree->root == node);
382 } else {
383 VERIFY(parent->llink == node || parent->rlink == node);
384 }
385 if (node) {
386 VERIFY(node->parent == parent);
387 if (parent) {
388 if (parent->llink == node) {
389 VERIFY(tree->cmp_func(parent->key, node->key) > 0);
390 } else {
391 ASSERT(parent->rlink == node);
392 VERIFY(tree->cmp_func(parent->key, node->key) < 0);
393 }
394 }
395 unsigned lweight, rweight;
396 if (!node_verify(tree, node, node->llink, &lweight) ||
397 !node_verify(tree, node, node->rlink, &rweight))
398 return false;
399 VERIFY(WEIGHT(node->llink) == lweight);
400 VERIFY(WEIGHT(node->rlink) == rweight);
401 VERIFY(node->weight == lweight + rweight);
402 VERIFY(lweight * 1000U >= node->weight * 292U);
403 VERIFY(lweight * 1000U <= node->weight * 708U);
404 *weight = lweight + rweight;
405 } else {
406 *weight = 1;
407 }
408 return true;
409}
410
411bool
413{
414 if (tree->root) {
415 VERIFY(tree->count > 0);
416 VERIFY(tree->count + 1 == tree->root->weight);
417 } else {
418 VERIFY(tree->count == 0);
419 }
420 unsigned root_weight;
421 return node_verify(tree, NULL, tree->root, &root_weight);
422}
423
424wb_itor*
426{
427 wb_itor* itor = MALLOC(sizeof(*itor));
428 if (itor) {
429 itor->tree = tree;
430 itor->node = NULL;
431 }
432 return itor;
433}
434
437{
438 dict_itor* itor = MALLOC(sizeof(*itor));
439 if (itor) {
440 if (!(itor->_itor = wb_itor_new(tree))) {
441 FREE(itor);
442 return NULL;
443 }
444 itor->_vtable = &wb_tree_itor_vtable;
445 }
446 return itor;
447}
448
450bool wb_itor_valid(const wb_itor* itor) { return tree_iterator_valid(itor); }
452bool wb_itor_next(wb_itor* itor) { return tree_iterator_next(itor); }
453bool wb_itor_prev(wb_itor* itor) { return tree_iterator_prev(itor); }
454bool wb_itor_nextn(wb_itor* itor, size_t count) { return tree_iterator_nextn(itor, count); } /* TODO: speed up */
455bool wb_itor_prevn(wb_itor* itor, size_t count) { return tree_iterator_prevn(itor, count); } /* TODO: speed up */
456bool wb_itor_first(wb_itor* itor) { return tree_iterator_first(itor); }
457bool wb_itor_last(wb_itor* itor) { return tree_iterator_last(itor); }
458bool wb_itor_search(wb_itor* itor, const void* key) { return tree_iterator_search(itor, key); }
459bool wb_itor_search_le(wb_itor* itor, const void* key) { return tree_iterator_search_le(itor, key); }
460bool wb_itor_search_lt(wb_itor* itor, const void* key) { return tree_iterator_search_lt(itor, key); }
461bool wb_itor_search_ge(wb_itor* itor, const void* key) { return tree_iterator_search_ge(itor, key); }
462bool wb_itor_search_gt(wb_itor* itor, const void* key) { return tree_iterator_search_gt(itor, key); }
463const void* wb_itor_key(const wb_itor* itor) { return tree_iterator_key(itor); }
464void** wb_itor_datum(wb_itor* itor) { return tree_iterator_datum(itor); }
465int wb_itor_compare(const wb_itor* i1, const wb_itor* i2) { return tree_iterator_compare(i1, i2); }
466
467bool
469{
470 if (!itor->node)
471 return false;
472 remove_node(itor->tree, itor->node);
473 itor->node = NULL;
474 return true;
475}
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)
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
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
wb_node * node
Definition wb_tree.c:79
wb_tree * tree
Definition wb_tree.c:79
wb_node * parent
Definition wb_tree.c:68
void * datum
Definition wb_tree.c:68
uint32_t weight
Definition wb_tree.c:69
void * key
Definition wb_tree.c:68
wb_node * rlink
Definition wb_tree.c:68
wb_node * llink
Definition wb_tree.c:68
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
bool wb_itor_first(wb_itor *itor)
Definition wb_tree.c:456
size_t wb_tree_clear(wb_tree *tree, dict_delete_func delete_func)
Definition wb_tree.c:324
void wb_itor_free(wb_itor *itor)
Definition wb_tree.c:449
void ** wb_tree_search_ge(wb_tree *tree, const void *key)
Definition wb_tree.c:155
void ** wb_tree_search_le(wb_tree *tree, const void *key)
Definition wb_tree.c:153
size_t wb_tree_count(const wb_tree *tree)
Definition wb_tree.c:356
int wb_itor_compare(const wb_itor *i1, const wb_itor *i2)
Definition wb_tree.c:465
bool wb_itor_last(wb_itor *itor)
Definition wb_tree.c:457
bool wb_itor_search_lt(wb_itor *itor, const void *key)
Definition wb_tree.c:460
const void * wb_itor_key(const wb_itor *itor)
Definition wb_tree.c:463
bool wb_itor_remove(wb_itor *itor)
Definition wb_tree.c:468
bool wb_itor_search_gt(wb_itor *itor, const void *key)
Definition wb_tree.c:462
void ** wb_tree_search_lt(wb_tree *tree, const void *key)
Definition wb_tree.c:154
size_t wb_tree_traverse(wb_tree *tree, dict_visit_func visit, void *user_data)
Definition wb_tree.c:325
wb_tree * wb_tree_new(dict_compare_func cmp_func)
Definition wb_tree.c:124
dict_insert_result wb_tree_insert(wb_tree *tree, void *key)
Definition wb_tree.c:235
dict * wb_dict_new(dict_compare_func cmp_func)
Definition wb_tree.c:139
bool wb_itor_prevn(wb_itor *itor, size_t count)
Definition wb_tree.c:455
dict_itor * wb_dict_itor_new(wb_tree *tree)
Definition wb_tree.c:436
bool wb_itor_search(wb_itor *itor, const void *key)
Definition wb_tree.c:458
bool wb_tree_verify(const wb_tree *tree)
Definition wb_tree.c:412
void ** wb_itor_datum(wb_itor *itor)
Definition wb_tree.c:464
bool wb_itor_search_ge(wb_itor *itor, const void *key)
Definition wb_tree.c:461
bool wb_itor_nextn(wb_itor *itor, size_t count)
Definition wb_tree.c:454
bool wb_itor_search_le(wb_itor *itor, const void *key)
Definition wb_tree.c:459
void wb_itor_invalidate(wb_itor *itor)
Definition wb_tree.c:451
size_t wb_tree_free(wb_tree *tree, dict_delete_func delete_func)
Definition wb_tree.c:323
#define WEIGHT(n)
Definition wb_tree.c:72
bool wb_itor_valid(const wb_itor *itor)
Definition wb_tree.c:450
bool wb_itor_prev(wb_itor *itor)
Definition wb_tree.c:453
bool wb_tree_select(wb_tree *tree, size_t n, const void **key, void **datum)
Definition wb_tree.c:328
size_t wb_tree_min_path_length(const wb_tree *tree)
Definition wb_tree.c:357
dict_remove_result wb_tree_remove(wb_tree *tree, const void *key)
Definition wb_tree.c:313
bool wb_itor_next(wb_itor *itor)
Definition wb_tree.c:452
void ** wb_tree_search(wb_tree *tree, const void *key)
Definition wb_tree.c:152
void ** wb_tree_search_gt(wb_tree *tree, const void *key)
Definition wb_tree.c:156
wb_itor * wb_itor_new(wb_tree *tree)
Definition wb_tree.c:425
size_t wb_tree_max_path_length(const wb_tree *tree)
Definition wb_tree.c:358
size_t wb_tree_total_path_length(const wb_tree *tree)
Definition wb_tree.c:359