1 /* wmem_tree.c
2 * Wireshark Memory Manager Red-Black Tree
3 * Based on the red-black tree implementation in epan/emem.*
4 * Copyright 2013, Evan Huus <eapache@gmail.com>
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 #include "config.h"
14
15 #include <string.h>
16 #include <stdio.h>
17 #include <glib.h>
18
19 #include "wmem-int.h"
20 #include "wmem_core.h"
21 #include "wmem_strutl.h"
22 #include "wmem_tree.h"
23 #include "wmem_tree-int.h"
24 #include "wmem_user_cb.h"
25
26
27 static wmem_tree_node_t *
node_uncle(wmem_tree_node_t * node)28 node_uncle(wmem_tree_node_t *node)
29 {
30 wmem_tree_node_t *parent, *grandparent;
31
32 parent = node->parent;
33 if (parent == NULL) {
34 return NULL;
35 }
36
37 grandparent = parent->parent;
38 if (grandparent == NULL) {
39 return NULL;
40 }
41
42 if (parent == grandparent->left) {
43 return grandparent->right;
44 }
45 else {
46 return grandparent->left;
47 }
48 }
49
50 static void rb_insert_case1(wmem_tree_t *tree, wmem_tree_node_t *node);
51 static void rb_insert_case2(wmem_tree_t *tree, wmem_tree_node_t *node);
52
53 static void
rotate_left(wmem_tree_t * tree,wmem_tree_node_t * node)54 rotate_left(wmem_tree_t *tree, wmem_tree_node_t *node)
55 {
56 if (node->parent) {
57 if (node->parent->left == node) {
58 node->parent->left = node->right;
59 }
60 else {
61 node->parent->right = node->right;
62 }
63 }
64 else {
65 tree->root = node->right;
66 }
67
68 node->right->parent = node->parent;
69 node->parent = node->right;
70 node->right = node->right->left;
71 if (node->right) {
72 node->right->parent = node;
73 }
74 node->parent->left = node;
75
76 if (tree->post_rotation_cb) {
77 tree->post_rotation_cb (node);
78 }
79 }
80
81 static void
rotate_right(wmem_tree_t * tree,wmem_tree_node_t * node)82 rotate_right(wmem_tree_t *tree, wmem_tree_node_t *node)
83 {
84 if (node->parent) {
85 if (node->parent->left == node) {
86 node->parent->left = node->left;
87 }
88 else {
89 node->parent->right = node->left;
90 }
91 }
92 else {
93 tree->root = node->left;
94 }
95
96 node->left->parent = node->parent;
97 node->parent = node->left;
98 node->left = node->left->right;
99 if (node->left) {
100 node->left->parent = node;
101 }
102 node->parent->right = node;
103
104
105 if (tree->post_rotation_cb) {
106 tree->post_rotation_cb (node);
107 }
108 }
109
110 static void
rb_insert_case5(wmem_tree_t * tree,wmem_tree_node_t * node)111 rb_insert_case5(wmem_tree_t *tree, wmem_tree_node_t *node)
112 {
113 wmem_tree_node_t *parent, *grandparent;
114
115 parent = node->parent;
116 grandparent = parent->parent;
117
118 parent->color = WMEM_NODE_COLOR_BLACK;
119 grandparent->color = WMEM_NODE_COLOR_RED;
120
121 if (node == parent->left && parent == grandparent->left) {
122 rotate_right(tree, grandparent);
123 }
124 else {
125 rotate_left(tree, grandparent);
126 }
127 }
128
129 static void
rb_insert_case4(wmem_tree_t * tree,wmem_tree_node_t * node)130 rb_insert_case4(wmem_tree_t *tree, wmem_tree_node_t *node)
131 {
132 wmem_tree_node_t *parent, *grandparent;
133
134 parent = node->parent;
135 grandparent = parent->parent;
136 if (!grandparent) {
137 return;
138 }
139
140 if (node == parent->right && parent == grandparent->left) {
141 rotate_left(tree, parent);
142 node = node->left;
143 }
144 else if (node == parent->left && parent == grandparent->right) {
145 rotate_right(tree, parent);
146 node = node->right;
147 }
148
149 rb_insert_case5(tree, node);
150 }
151
152 static void
rb_insert_case3(wmem_tree_t * tree,wmem_tree_node_t * node)153 rb_insert_case3(wmem_tree_t *tree, wmem_tree_node_t *node)
154 {
155 wmem_tree_node_t *parent, *grandparent, *uncle;
156
157 uncle = node_uncle(node);
158
159 if (uncle && uncle->color == WMEM_NODE_COLOR_RED) {
160 parent = node->parent;
161 grandparent = parent->parent;
162
163 parent->color = WMEM_NODE_COLOR_BLACK;
164 uncle->color = WMEM_NODE_COLOR_BLACK;
165 grandparent->color = WMEM_NODE_COLOR_RED;
166
167 rb_insert_case1(tree, grandparent);
168 }
169 else {
170 rb_insert_case4(tree, node);
171 }
172 }
173
174 static void
rb_insert_case2(wmem_tree_t * tree,wmem_tree_node_t * node)175 rb_insert_case2(wmem_tree_t *tree, wmem_tree_node_t *node)
176 {
177 /* parent is always non-NULL here */
178 if (node->parent->color == WMEM_NODE_COLOR_RED) {
179 rb_insert_case3(tree, node);
180 }
181 }
182
183 static void
rb_insert_case1(wmem_tree_t * tree,wmem_tree_node_t * node)184 rb_insert_case1(wmem_tree_t *tree, wmem_tree_node_t *node)
185 {
186 wmem_tree_node_t *parent = node->parent;
187
188 if (parent == NULL) {
189 node->color = WMEM_NODE_COLOR_BLACK;
190 }
191 else {
192 rb_insert_case2(tree, node);
193 }
194 }
195
196 wmem_tree_t *
wmem_tree_new(wmem_allocator_t * allocator)197 wmem_tree_new(wmem_allocator_t *allocator)
198 {
199 wmem_tree_t *tree;
200
201 tree = wmem_new0(allocator, wmem_tree_t);
202 tree->metadata_allocator = allocator;
203 tree->data_allocator = allocator;
204
205 return tree;
206 }
207
208 static gboolean
wmem_tree_reset_cb(wmem_allocator_t * allocator _U_,wmem_cb_event_t event,void * user_data)209 wmem_tree_reset_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event,
210 void *user_data)
211 {
212 wmem_tree_t *tree = (wmem_tree_t *)user_data;
213
214 tree->root = NULL;
215
216 if (event == WMEM_CB_DESTROY_EVENT) {
217 wmem_unregister_callback(tree->metadata_allocator, tree->metadata_scope_cb_id);
218 wmem_free(tree->metadata_allocator, tree);
219 }
220
221 return TRUE;
222 }
223
224 static gboolean
wmem_tree_destroy_cb(wmem_allocator_t * allocator _U_,wmem_cb_event_t event _U_,void * user_data)225 wmem_tree_destroy_cb(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_,
226 void *user_data)
227 {
228 wmem_tree_t *tree = (wmem_tree_t *)user_data;
229
230 wmem_unregister_callback(tree->data_allocator, tree->data_scope_cb_id);
231
232 return FALSE;
233 }
234
235 wmem_tree_t *
wmem_tree_new_autoreset(wmem_allocator_t * metadata_scope,wmem_allocator_t * data_scope)236 wmem_tree_new_autoreset(wmem_allocator_t *metadata_scope, wmem_allocator_t *data_scope)
237 {
238 wmem_tree_t *tree;
239
240 tree = wmem_new0(metadata_scope, wmem_tree_t);
241 tree->metadata_allocator = metadata_scope;
242 tree->data_allocator = data_scope;
243
244 tree->metadata_scope_cb_id = wmem_register_callback(metadata_scope, wmem_tree_destroy_cb,
245 tree);
246 tree->data_scope_cb_id = wmem_register_callback(data_scope, wmem_tree_reset_cb,
247 tree);
248
249 return tree;
250 }
251
252 static void
free_tree_node(wmem_allocator_t * allocator,wmem_tree_node_t * node,gboolean free_keys,gboolean free_values)253 free_tree_node(wmem_allocator_t *allocator, wmem_tree_node_t* node, gboolean free_keys, gboolean free_values)
254 {
255 if (node == NULL) {
256 return;
257 }
258
259 if (node->left) {
260 free_tree_node(allocator, node->left, free_keys, free_values);
261 }
262
263 if (node->is_subtree) {
264 wmem_tree_destroy((wmem_tree_t *)node->data, free_keys, free_values);
265 node->data = NULL;
266 }
267
268 if (node->right) {
269 free_tree_node(allocator, node->right, free_keys, free_values);
270 }
271
272 if (free_keys) {
273 wmem_free(allocator, (void*)node->key);
274 }
275
276 if (free_values) {
277 wmem_free(allocator, node->data);
278 }
279 wmem_free(allocator, node);
280 }
281
282 void
wmem_tree_destroy(wmem_tree_t * tree,gboolean free_keys,gboolean free_values)283 wmem_tree_destroy(wmem_tree_t *tree, gboolean free_keys, gboolean free_values)
284 {
285 free_tree_node(tree->data_allocator, tree->root, free_keys, free_values);
286 if (tree->metadata_allocator) {
287 wmem_unregister_callback(tree->metadata_allocator, tree->metadata_scope_cb_id);
288 }
289 if (tree->data_allocator) {
290 wmem_unregister_callback(tree->data_allocator, tree->data_scope_cb_id);
291 }
292 wmem_free(tree->metadata_allocator, tree);
293 }
294
295 gboolean
wmem_tree_is_empty(wmem_tree_t * tree)296 wmem_tree_is_empty(wmem_tree_t *tree)
297 {
298 return tree->root == NULL;
299 }
300
301 static gboolean
count_nodes(const void * key _U_,void * value _U_,void * userdata)302 count_nodes(const void *key _U_, void *value _U_, void *userdata)
303 {
304 guint* count = (guint*)userdata;
305 (*count)++;
306 return FALSE;
307 }
308
309 guint
wmem_tree_count(wmem_tree_t * tree)310 wmem_tree_count(wmem_tree_t* tree)
311 {
312 guint count = 0;
313
314 /* Recursing through the tree counting each node is the simplest approach.
315 We don't keep track of the count within the tree because it can get
316 complicated with subtrees within the tree */
317 wmem_tree_foreach(tree, count_nodes, &count);
318
319 return count;
320 }
321
322 static wmem_tree_node_t *
create_node(wmem_allocator_t * allocator,wmem_tree_node_t * parent,const void * key,void * data,wmem_node_color_t color,gboolean is_subtree)323 create_node(wmem_allocator_t *allocator, wmem_tree_node_t *parent, const void *key,
324 void *data, wmem_node_color_t color, gboolean is_subtree)
325 {
326 wmem_tree_node_t *node;
327
328 node = wmem_new(allocator, wmem_tree_node_t);
329
330 node->left = NULL;
331 node->right = NULL;
332 node->parent = parent;
333
334 node->key = key;
335 node->data = data;
336
337 node->color = color;
338 node->is_subtree = is_subtree;
339 node->is_removed = FALSE;
340
341 return node;
342 }
343
344 #define CREATE_DATA(TRANSFORM, DATA) ((TRANSFORM) ? (TRANSFORM)(DATA) : (DATA))
345
346
347 /**
348 * return inserted node
349 */
350 static wmem_tree_node_t *
lookup_or_insert32_node(wmem_tree_t * tree,guint32 key,void * (* func)(void *),void * data,gboolean is_subtree,gboolean replace)351 lookup_or_insert32_node(wmem_tree_t *tree, guint32 key,
352 void*(*func)(void*), void* data, gboolean is_subtree, gboolean replace)
353 {
354 wmem_tree_node_t *node = tree->root;
355 wmem_tree_node_t *new_node = NULL;
356
357 /* is this the first node ?*/
358 if (!node) {
359 new_node = create_node(tree->data_allocator, NULL, GUINT_TO_POINTER(key),
360 CREATE_DATA(func, data), WMEM_NODE_COLOR_BLACK, is_subtree);
361 tree->root = new_node;
362 return new_node;
363 }
364
365 /* it was not the new root so walk the tree until we find where to
366 * insert this new leaf.
367 */
368 while (!new_node) {
369 /* this node already exists, so just return the data pointer*/
370 if (key == GPOINTER_TO_UINT(node->key)) {
371 if (replace) {
372 node->data = CREATE_DATA(func, data);
373 }
374 return node;
375 }
376 else if (key < GPOINTER_TO_UINT(node->key)) {
377 if (node->left) {
378 node = node->left;
379 }
380 else {
381 /* new node to the left */
382 new_node = create_node(tree->data_allocator, node, GUINT_TO_POINTER(key),
383 CREATE_DATA(func, data), WMEM_NODE_COLOR_RED,
384 is_subtree);
385 node->left = new_node;
386 }
387 }
388 else if (key > GPOINTER_TO_UINT(node->key)) {
389 if (node->right) {
390 node = node->right;
391 }
392 else {
393 /* new node to the right */
394 new_node = create_node(tree->data_allocator, node, GUINT_TO_POINTER(key),
395 CREATE_DATA(func, data), WMEM_NODE_COLOR_RED,
396 is_subtree);
397 node->right = new_node;
398 }
399 }
400 }
401
402 /* node will now point to the newly created node */
403 rb_insert_case1(tree, new_node);
404
405 return new_node;
406 }
407
408
409 static void *
lookup_or_insert32(wmem_tree_t * tree,guint32 key,void * (* func)(void *),void * data,gboolean is_subtree,gboolean replace)410 lookup_or_insert32(wmem_tree_t *tree, guint32 key,
411 void*(*func)(void*), void* data, gboolean is_subtree, gboolean replace)
412 {
413 wmem_tree_node_t *node = lookup_or_insert32_node(tree, key, func, data, is_subtree, replace);
414 return node->data;
415 }
416
417 static void *
wmem_tree_lookup(wmem_tree_t * tree,const void * key,compare_func cmp)418 wmem_tree_lookup(wmem_tree_t *tree, const void *key, compare_func cmp)
419 {
420 wmem_tree_node_t *node;
421
422 if (tree == NULL || key == NULL) {
423 return NULL;
424 }
425
426 node = tree->root;
427
428 while (node) {
429 int result = cmp(key, node->key);
430 if (result == 0) {
431 return node->data;
432 }
433 else if (result < 0) {
434 node = node->left;
435 }
436 else if (result > 0) {
437 node = node->right;
438 }
439 }
440
441 return NULL;
442 }
443
444 wmem_tree_node_t *
wmem_tree_insert(wmem_tree_t * tree,const void * key,void * data,compare_func cmp)445 wmem_tree_insert(wmem_tree_t *tree, const void *key, void *data, compare_func cmp)
446 {
447 wmem_tree_node_t *node = tree->root;
448 wmem_tree_node_t *new_node = NULL;
449
450 /* is this the first node ?*/
451 if (!node) {
452 tree->root = create_node(tree->data_allocator, node, key,
453 data, WMEM_NODE_COLOR_BLACK, FALSE);
454 return tree->root;
455 }
456
457 /* it was not the new root so walk the tree until we find where to
458 * insert this new leaf.
459 */
460 while (!new_node) {
461 int result = cmp(key, node->key);
462 if (result == 0) {
463 node->data = data;
464 node->is_removed = data ? FALSE : TRUE;
465 return node;
466 }
467 else if (result < 0) {
468 if (node->left) {
469 node = node->left;
470 }
471 else {
472 new_node = create_node(tree->data_allocator, node, key,
473 data, WMEM_NODE_COLOR_RED, FALSE);
474 node->left = new_node;
475 }
476 }
477 else if (result > 0) {
478 if (node->right) {
479 node = node->right;
480 }
481 else {
482 /* new node to the right */
483 new_node = create_node(tree->data_allocator, node, key,
484 data, WMEM_NODE_COLOR_RED, FALSE);
485 node->right = new_node;
486 }
487 }
488 }
489
490 /* node will now point to the newly created node */
491 rb_insert_case1(tree, new_node);
492
493 return new_node;
494 }
495
496 void
wmem_tree_insert32(wmem_tree_t * tree,guint32 key,void * data)497 wmem_tree_insert32(wmem_tree_t *tree, guint32 key, void *data)
498 {
499 lookup_or_insert32(tree, key, NULL, data, FALSE, TRUE);
500 }
501
502 void *
wmem_tree_lookup32(wmem_tree_t * tree,guint32 key)503 wmem_tree_lookup32(wmem_tree_t *tree, guint32 key)
504 {
505 wmem_tree_node_t *node = tree->root;
506
507 while (node) {
508 if (key == GPOINTER_TO_UINT(node->key)) {
509 return node->data;
510 }
511 else if (key < GPOINTER_TO_UINT(node->key)) {
512 node = node->left;
513 }
514 else if (key > GPOINTER_TO_UINT(node->key)) {
515 node = node->right;
516 }
517 }
518
519 return NULL;
520 }
521
522 void *
wmem_tree_lookup32_le(wmem_tree_t * tree,guint32 key)523 wmem_tree_lookup32_le(wmem_tree_t *tree, guint32 key)
524 {
525 wmem_tree_node_t *node = tree->root;
526
527 while (node) {
528 if (key == GPOINTER_TO_UINT(node->key)) {
529 return node->data;
530 }
531 else if (key < GPOINTER_TO_UINT(node->key)) {
532 if (node->left == NULL) {
533 break;
534 }
535 node = node->left;
536 }
537 else if (key > GPOINTER_TO_UINT(node->key)) {
538 if (node->right == NULL) {
539 break;
540 }
541 node = node->right;
542 }
543 }
544
545 if (!node) {
546 return NULL;
547 }
548
549 /* If we are still at the root of the tree this means that this node
550 * is either smaller than the search key and then we return this
551 * node or else there is no smaller key available and then
552 * we return NULL.
553 */
554 if (node->parent == NULL) {
555 if (key > GPOINTER_TO_UINT(node->key)) {
556 return node->data;
557 } else {
558 return NULL;
559 }
560 }
561
562 if (GPOINTER_TO_UINT(node->key) <= key) {
563 /* if our key is <= the search key, we have the right node */
564 return node->data;
565 }
566 else if (node == node->parent->left) {
567 /* our key is bigger than the search key and we're a left child,
568 * we have to check if any of our ancestors are smaller. */
569 while (node) {
570 if (key > GPOINTER_TO_UINT(node->key)) {
571 return node->data;
572 }
573 node=node->parent;
574 }
575 return NULL;
576 }
577 else {
578 /* our key is bigger than the search key and we're a right child,
579 * our parent is the one we want */
580 return node->parent->data;
581 }
582 }
583
584 void *
wmem_tree_remove32(wmem_tree_t * tree,guint32 key)585 wmem_tree_remove32(wmem_tree_t *tree, guint32 key)
586 {
587 void *ret = wmem_tree_lookup32(tree, key);
588 if (ret) {
589 /* Not really a remove, but set data to NULL to mark node with is_removed */
590 wmem_tree_insert32(tree, key, NULL);
591 }
592 return ret;
593 }
594
595 void
wmem_tree_insert_string(wmem_tree_t * tree,const gchar * k,void * v,guint32 flags)596 wmem_tree_insert_string(wmem_tree_t* tree, const gchar* k, void* v, guint32 flags)
597 {
598 char *key;
599 compare_func cmp;
600
601 key = wmem_strdup(tree->data_allocator, k);
602
603 if (flags & WMEM_TREE_STRING_NOCASE) {
604 cmp = (compare_func)g_ascii_strcasecmp;
605 } else {
606 cmp = (compare_func)strcmp;
607 }
608
609 wmem_tree_insert(tree, key, v, cmp);
610 }
611
612 void *
wmem_tree_lookup_string(wmem_tree_t * tree,const gchar * k,guint32 flags)613 wmem_tree_lookup_string(wmem_tree_t* tree, const gchar* k, guint32 flags)
614 {
615 compare_func cmp;
616
617 if (flags & WMEM_TREE_STRING_NOCASE) {
618 cmp = (compare_func)g_ascii_strcasecmp;
619 } else {
620 cmp = (compare_func)strcmp;
621 }
622
623 return wmem_tree_lookup(tree, k, cmp);
624 }
625
626 void *
wmem_tree_remove_string(wmem_tree_t * tree,const gchar * k,guint32 flags)627 wmem_tree_remove_string(wmem_tree_t* tree, const gchar* k, guint32 flags)
628 {
629 void *ret = wmem_tree_lookup_string(tree, k, flags);
630 if (ret) {
631 /* Not really a remove, but set data to NULL to mark node with is_removed */
632 wmem_tree_insert_string(tree, k, NULL, flags);
633 }
634 return ret;
635 }
636
637 static void *
create_sub_tree(void * d)638 create_sub_tree(void* d)
639 {
640 return wmem_tree_new(((wmem_tree_t *)d)->data_allocator);
641 }
642
643 void
wmem_tree_insert32_array(wmem_tree_t * tree,wmem_tree_key_t * key,void * data)644 wmem_tree_insert32_array(wmem_tree_t *tree, wmem_tree_key_t *key, void *data)
645 {
646 wmem_tree_t *insert_tree = NULL;
647 wmem_tree_key_t *cur_key;
648 guint32 i, insert_key32 = 0;
649
650 for (cur_key = key; cur_key->length > 0; cur_key++) {
651 for (i = 0; i < cur_key->length; i++) {
652 /* Insert using the previous key32 */
653 if (!insert_tree) {
654 insert_tree = tree;
655 } else {
656 insert_tree = (wmem_tree_t *)lookup_or_insert32(insert_tree,
657 insert_key32, create_sub_tree, tree, TRUE, FALSE);
658 }
659 insert_key32 = cur_key->key[i];
660 }
661 }
662
663 ASSERT(insert_tree);
664
665 wmem_tree_insert32(insert_tree, insert_key32, data);
666 }
667
668 static void *
wmem_tree_lookup32_array_helper(wmem_tree_t * tree,wmem_tree_key_t * key,void * (* helper)(wmem_tree_t *,guint32))669 wmem_tree_lookup32_array_helper(wmem_tree_t *tree, wmem_tree_key_t *key,
670 void*(*helper)(wmem_tree_t*, guint32))
671 {
672 wmem_tree_t *lookup_tree = NULL;
673 wmem_tree_key_t *cur_key;
674 guint32 i, lookup_key32 = 0;
675
676 if (!tree || !key) {
677 return NULL;
678 }
679
680 for (cur_key = key; cur_key->length > 0; cur_key++) {
681 for (i = 0; i < cur_key->length; i++) {
682 /* Lookup using the previous key32 */
683 if (!lookup_tree) {
684 lookup_tree = tree;
685 }
686 else {
687 lookup_tree =
688 (wmem_tree_t *)(*helper)(lookup_tree, lookup_key32);
689 if (!lookup_tree) {
690 return NULL;
691 }
692 }
693 lookup_key32 = cur_key->key[i];
694 }
695 }
696
697 /* Assert if we didn't get any valid keys */
698 ASSERT(lookup_tree);
699
700 return (*helper)(lookup_tree, lookup_key32);
701 }
702
703 void *
wmem_tree_lookup32_array(wmem_tree_t * tree,wmem_tree_key_t * key)704 wmem_tree_lookup32_array(wmem_tree_t *tree, wmem_tree_key_t *key)
705 {
706 return wmem_tree_lookup32_array_helper(tree, key, wmem_tree_lookup32);
707 }
708
709 void *
wmem_tree_lookup32_array_le(wmem_tree_t * tree,wmem_tree_key_t * key)710 wmem_tree_lookup32_array_le(wmem_tree_t *tree, wmem_tree_key_t *key)
711 {
712 return wmem_tree_lookup32_array_helper(tree, key, wmem_tree_lookup32_le);
713 }
714
715 static gboolean
wmem_tree_foreach_nodes(wmem_tree_node_t * node,wmem_foreach_func callback,void * user_data)716 wmem_tree_foreach_nodes(wmem_tree_node_t* node, wmem_foreach_func callback,
717 void *user_data)
718 {
719 gboolean stop_traverse = FALSE;
720
721 if (!node) {
722 return FALSE;
723 }
724
725 if (node->left) {
726 if (wmem_tree_foreach_nodes(node->left, callback, user_data)) {
727 return TRUE;
728 }
729 }
730
731 if (node->is_subtree) {
732 stop_traverse = wmem_tree_foreach((wmem_tree_t *)node->data,
733 callback, user_data);
734 } else if (!node->is_removed) {
735 /* No callback for "removed" nodes */
736 stop_traverse = callback(node->key, node->data, user_data);
737 }
738
739 if (stop_traverse) {
740 return TRUE;
741 }
742
743 if(node->right) {
744 if (wmem_tree_foreach_nodes(node->right, callback, user_data)) {
745 return TRUE;
746 }
747 }
748
749 return FALSE;
750 }
751
752 gboolean
wmem_tree_foreach(wmem_tree_t * tree,wmem_foreach_func callback,void * user_data)753 wmem_tree_foreach(wmem_tree_t* tree, wmem_foreach_func callback,
754 void *user_data)
755 {
756 if(!tree->root)
757 return FALSE;
758
759 return wmem_tree_foreach_nodes(tree->root, callback, user_data);
760 }
761
762 static void wmem_print_subtree(wmem_tree_t *tree, guint32 level, wmem_printer_func key_printer, wmem_printer_func data_printer);
763
764 static void
wmem_print_indent(guint32 level)765 wmem_print_indent(guint32 level) {
766 guint32 i;
767 for (i=0; i<level; i++) {
768 printf(" ");
769 }
770 }
771
772 static void
wmem_tree_print_nodes(const char * prefix,wmem_tree_node_t * node,guint32 level,wmem_printer_func key_printer,wmem_printer_func data_printer)773 wmem_tree_print_nodes(const char *prefix, wmem_tree_node_t *node, guint32 level,
774 wmem_printer_func key_printer, wmem_printer_func data_printer)
775 {
776 if (!node)
777 return;
778
779 wmem_print_indent(level);
780
781 printf("%sNODE:%p parent:%p left:%p right:%p colour:%s key:%p %s:%p\n",
782 prefix,
783 (void *)node, (void *)node->parent,
784 (void *)node->left, (void *)node->right,
785 node->color?"Black":"Red", node->key,
786 node->is_subtree?"tree":"data", node->data);
787 if (key_printer) {
788 wmem_print_indent(level);
789 key_printer(node->key);
790 printf("\n");
791 }
792 if (data_printer && !node->is_subtree) {
793 wmem_print_indent(level);
794 data_printer(node->data);
795 printf("\n");
796 }
797
798 if (node->left)
799 wmem_tree_print_nodes("L-", node->left, level+1, key_printer, data_printer);
800 if (node->right)
801 wmem_tree_print_nodes("R-", node->right, level+1, key_printer, data_printer);
802
803 if (node->is_subtree)
804 wmem_print_subtree((wmem_tree_t *)node->data, level+1, key_printer, data_printer);
805 }
806
807
808 static void
wmem_print_subtree(wmem_tree_t * tree,guint32 level,wmem_printer_func key_printer,wmem_printer_func data_printer)809 wmem_print_subtree(wmem_tree_t *tree, guint32 level, wmem_printer_func key_printer, wmem_printer_func data_printer)
810 {
811 if (!tree)
812 return;
813
814 wmem_print_indent(level);
815
816 printf("WMEM tree:%p root:%p\n", (void *)tree, (void *)tree->root);
817 if (tree->root) {
818 wmem_tree_print_nodes("Root-", tree->root, level, key_printer, data_printer);
819 }
820 }
821
822 void
wmem_print_tree(wmem_tree_t * tree,wmem_printer_func key_printer,wmem_printer_func data_printer)823 wmem_print_tree(wmem_tree_t *tree, wmem_printer_func key_printer, wmem_printer_func data_printer)
824 {
825 wmem_print_subtree(tree, 0, key_printer, data_printer);
826 }
827 /*
828 * Editor modelines - https://www.wireshark.org/tools/modelines.html
829 *
830 * Local variables:
831 * c-basic-offset: 4
832 * tab-width: 8
833 * indent-tabs-mode: nil
834 * End:
835 *
836 * vi: set shiftwidth=4 tabstop=8 expandtab:
837 * :indentSize=4:tabSize=8:noTabs=true:
838 */
839