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