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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include "wmem_core.h"
35 #include "wmem_tree.h"
36 #include "wmem_user_cb.h"
38 typedef enum _wmem_node_color_t
{
43 struct _wmem_tree_node_t
{
44 struct _wmem_tree_node_t
*parent
;
45 struct _wmem_tree_node_t
*left
;
46 struct _wmem_tree_node_t
*right
;
51 wmem_node_color_t color
;
55 typedef struct _wmem_tree_node_t wmem_tree_node_t
;
58 wmem_allocator_t
*master
;
59 wmem_allocator_t
*allocator
;
60 wmem_tree_node_t
*root
;
65 static wmem_tree_node_t
*
66 node_uncle(wmem_tree_node_t
*node
)
68 wmem_tree_node_t
*parent
, *grandparent
;
70 parent
= node
->parent
;
75 grandparent
= parent
->parent
;
76 if (grandparent
== NULL
) {
80 if (parent
== grandparent
->left
) {
81 return grandparent
->right
;
84 return grandparent
->left
;
88 static void rb_insert_case1(wmem_tree_t
*tree
, wmem_tree_node_t
*node
);
89 static void rb_insert_case2(wmem_tree_t
*tree
, wmem_tree_node_t
*node
);
92 rotate_left(wmem_tree_t
*tree
, wmem_tree_node_t
*node
)
95 if (node
->parent
->left
== node
) {
96 node
->parent
->left
= node
->right
;
99 node
->parent
->right
= node
->right
;
103 tree
->root
= node
->right
;
106 node
->right
->parent
= node
->parent
;
107 node
->parent
= node
->right
;
108 node
->right
= node
->right
->left
;
110 node
->right
->parent
= node
;
112 node
->parent
->left
= node
;
116 rotate_right(wmem_tree_t
*tree
, wmem_tree_node_t
*node
)
119 if (node
->parent
->left
== node
) {
120 node
->parent
->left
= node
->left
;
123 node
->parent
->right
= node
->left
;
127 tree
->root
= node
->left
;
130 node
->left
->parent
= node
->parent
;
131 node
->parent
= node
->left
;
132 node
->left
= node
->left
->right
;
134 node
->left
->parent
= node
;
136 node
->parent
->right
= node
;
140 rb_insert_case5(wmem_tree_t
*tree
, wmem_tree_node_t
*node
)
142 wmem_tree_node_t
*parent
, *grandparent
;
144 parent
= node
->parent
;
145 grandparent
= parent
->parent
;
147 parent
->color
= WMEM_NODE_COLOR_BLACK
;
148 grandparent
->color
= WMEM_NODE_COLOR_RED
;
150 if (node
== parent
->left
&& parent
== grandparent
->left
) {
151 rotate_right(tree
, grandparent
);
154 rotate_left(tree
, grandparent
);
159 rb_insert_case4(wmem_tree_t
*tree
, wmem_tree_node_t
*node
)
161 wmem_tree_node_t
*parent
, *grandparent
;
163 parent
= node
->parent
;
164 grandparent
= parent
->parent
;
169 if (node
== parent
->right
&& parent
== grandparent
->left
) {
170 rotate_left(tree
, parent
);
173 else if (node
== parent
->left
&& parent
== grandparent
->right
) {
174 rotate_right(tree
, parent
);
178 rb_insert_case5(tree
, node
);
182 rb_insert_case3(wmem_tree_t
*tree
, wmem_tree_node_t
*node
)
184 wmem_tree_node_t
*parent
, *grandparent
, *uncle
;
186 uncle
= node_uncle(node
);
188 if (uncle
&& uncle
->color
== WMEM_NODE_COLOR_RED
) {
189 parent
= node
->parent
;
190 grandparent
= parent
->parent
;
192 parent
->color
= WMEM_NODE_COLOR_BLACK
;
193 uncle
->color
= WMEM_NODE_COLOR_BLACK
;
194 grandparent
->color
= WMEM_NODE_COLOR_RED
;
196 rb_insert_case1(tree
, grandparent
);
199 rb_insert_case4(tree
, node
);
204 rb_insert_case2(wmem_tree_t
*tree
, wmem_tree_node_t
*node
)
206 /* parent is always non-NULL here */
207 if (node
->parent
->color
== WMEM_NODE_COLOR_RED
) {
208 rb_insert_case3(tree
, node
);
213 rb_insert_case1(wmem_tree_t
*tree
, wmem_tree_node_t
*node
)
215 wmem_tree_node_t
*parent
= node
->parent
;
217 if (parent
== NULL
) {
218 node
->color
= WMEM_NODE_COLOR_BLACK
;
221 rb_insert_case2(tree
, node
);
226 wmem_tree_new(wmem_allocator_t
*allocator
)
230 tree
= wmem_new(allocator
, wmem_tree_t
);
231 tree
->master
= allocator
;
232 tree
->allocator
= allocator
;
239 wmem_tree_reset_cb(wmem_allocator_t
*allocator _U_
, wmem_cb_event_t event
,
242 wmem_tree_t
*tree
= (wmem_tree_t
*)user_data
;
246 if (event
== WMEM_CB_DESTROY_EVENT
) {
247 wmem_unregister_callback(tree
->master
, tree
->master_cb_id
);
248 wmem_free(tree
->master
, tree
);
255 wmem_tree_destroy_cb(wmem_allocator_t
*allocator _U_
, wmem_cb_event_t event _U_
,
258 wmem_tree_t
*tree
= (wmem_tree_t
*)user_data
;
260 wmem_unregister_callback(tree
->allocator
, tree
->slave_cb_id
);
266 wmem_tree_new_autoreset(wmem_allocator_t
*master
, wmem_allocator_t
*slave
)
270 tree
= wmem_new(master
, wmem_tree_t
);
271 tree
->master
= master
;
272 tree
->allocator
= slave
;
275 tree
->master_cb_id
= wmem_register_callback(master
, wmem_tree_destroy_cb
,
277 tree
->slave_cb_id
= wmem_register_callback(slave
, wmem_tree_reset_cb
,
284 wmem_tree_is_empty(wmem_tree_t
*tree
)
286 return tree
->root
== NULL
;
289 static wmem_tree_node_t
*
290 create_node(wmem_allocator_t
*allocator
, wmem_tree_node_t
*parent
, guint32 key
,
291 void *data
, wmem_node_color_t color
, gboolean is_subtree
)
293 wmem_tree_node_t
*node
;
295 node
= wmem_new(allocator
, wmem_tree_node_t
);
299 node
->parent
= parent
;
305 node
->is_subtree
= is_subtree
;
310 #define CREATE_DATA(TRANSFORM, DATA) ((TRANSFORM) ? (TRANSFORM)(DATA) : (DATA))
312 lookup_or_insert32(wmem_tree_t
*tree
, guint32 key
,
313 void*(*func
)(void*), void* data
, gboolean is_subtree
, gboolean replace
)
315 wmem_tree_node_t
*node
= tree
->root
;
316 wmem_tree_node_t
*new_node
= NULL
;
318 /* is this the first node ?*/
320 new_node
= create_node(tree
->allocator
, NULL
, key
,
321 CREATE_DATA(func
, data
), WMEM_NODE_COLOR_BLACK
, is_subtree
);
322 tree
->root
= new_node
;
323 return new_node
->data
;
326 /* it was not the new root so walk the tree until we find where to
327 * insert this new leaf.
330 /* this node already exists, so just return the data pointer*/
331 if (key
== node
->key32
) {
333 node
->data
= CREATE_DATA(func
, data
);
337 else if (key
< node
->key32
) {
342 /* new node to the left */
343 new_node
= create_node(tree
->allocator
, node
, key
,
344 CREATE_DATA(func
, data
), WMEM_NODE_COLOR_RED
,
346 node
->left
= new_node
;
349 else if (key
> node
->key32
) {
354 /* new node to the right */
355 new_node
= create_node(tree
->allocator
, node
, key
,
356 CREATE_DATA(func
, data
), WMEM_NODE_COLOR_RED
,
358 node
->right
= new_node
;
363 /* node will now point to the newly created node */
364 rb_insert_case1(tree
, new_node
);
366 return new_node
->data
;
370 wmem_tree_insert32(wmem_tree_t
*tree
, guint32 key
, void *data
)
372 lookup_or_insert32(tree
, key
, NULL
, data
, FALSE
, TRUE
);
376 wmem_tree_lookup32(wmem_tree_t
*tree
, guint32 key
)
378 wmem_tree_node_t
*node
= tree
->root
;
381 if (key
== node
->key32
) {
384 else if (key
< node
->key32
) {
387 else if (key
> node
->key32
) {
396 wmem_tree_lookup32_le(wmem_tree_t
*tree
, guint32 key
)
398 wmem_tree_node_t
*node
= tree
->root
;
401 if (key
== node
->key32
) {
404 else if (key
< node
->key32
) {
405 if (node
->left
== NULL
) {
410 else if (key
> node
->key32
) {
411 if (node
->right
== NULL
) {
422 /* If we are still at the root of the tree this means that this node
423 * is either smaller than the search key and then we return this
424 * node or else there is no smaller key available and then
427 if (node
->parent
== NULL
) {
428 if (key
> node
->key32
) {
435 if (node
->key32
<= key
) {
436 /* if our key is <= the search key, we have the right node */
439 else if (node
== node
->parent
->left
) {
440 /* our key is bigger than the search key and we're a left child,
441 * we have to check if any of our ancestors are smaller. */
443 if (key
> node
->key32
) {
451 /* our key is bigger than the search key and we're a right child,
452 * our parent is the one we want */
453 return node
->parent
->data
;
457 /* Strings are stored as an array of uint32 containing the string characters
458 with 4 characters in each uint32.
459 The first byte of the string is stored as the most significant byte.
460 If the string is not a multiple of 4 characters in length the last
461 uint32 containing the string bytes are padded with 0 bytes.
462 After the uint32's containing the string, there is one final terminator
463 uint32 with the value 0x00000001
466 pack_string(const gchar
*key
, guint32
*divx
, guint32 flags
)
468 guint32
*aligned
= NULL
;
469 guint32 len
= (guint32
) strlen(key
);
473 *divx
= (len
+3)/4 + 1;
475 aligned
= (guint32
*)wmem_alloc(NULL
, *divx
* sizeof (guint32
));
477 /* pack the bytes one one by one into guint32s */
479 for (i
= 0;i
< len
;i
++) {
482 ch
= (unsigned char)key
[i
];
483 if (flags
& WMEM_TREE_STRING_NOCASE
) {
495 /* add required padding to the last uint32 */
501 aligned
[i
/4-1] = tmp
;
504 /* add the terminator */
505 aligned
[*divx
-1] = 0x00000001;
511 wmem_tree_insert_string(wmem_tree_t
* tree
, const gchar
* k
, void* v
, guint32 flags
)
513 wmem_tree_key_t key
[2];
517 aligned
= pack_string(k
, &divx
, flags
);
519 key
[0].length
= divx
;
520 key
[0].key
= aligned
;
524 wmem_tree_insert32_array(tree
, key
, v
);
525 wmem_free(NULL
, aligned
);
529 wmem_tree_lookup_string(wmem_tree_t
* tree
, const gchar
* k
, guint32 flags
)
531 wmem_tree_key_t key
[2];
536 aligned
= pack_string(k
, &divx
, flags
);
538 key
[0].length
= divx
;
539 key
[0].key
= aligned
;
543 ret
= wmem_tree_lookup32_array(tree
, key
);
544 wmem_free(NULL
, aligned
);
549 create_sub_tree(void* d
)
551 return wmem_tree_new(((wmem_tree_t
*)d
)->allocator
);
555 wmem_tree_insert32_array(wmem_tree_t
*tree
, wmem_tree_key_t
*key
, void *data
)
557 wmem_tree_t
*insert_tree
= NULL
;
558 wmem_tree_key_t
*cur_key
;
559 guint32 i
, insert_key32
= 0;
561 for (cur_key
= key
; cur_key
->length
> 0; cur_key
++) {
562 for (i
= 0; i
< cur_key
->length
; i
++) {
563 /* Insert using the previous key32 */
567 insert_tree
= (wmem_tree_t
*)lookup_or_insert32(insert_tree
,
568 insert_key32
, create_sub_tree
, tree
, TRUE
, FALSE
);
570 insert_key32
= cur_key
->key
[i
];
574 g_assert(insert_tree
);
576 wmem_tree_insert32(insert_tree
, insert_key32
, data
);
580 wmem_tree_lookup32_array_helper(wmem_tree_t
*tree
, wmem_tree_key_t
*key
,
581 void*(*helper
)(wmem_tree_t
*, guint32
))
583 wmem_tree_t
*lookup_tree
= NULL
;
584 wmem_tree_key_t
*cur_key
;
585 guint32 i
, lookup_key32
= 0;
591 for (cur_key
= key
; cur_key
->length
> 0; cur_key
++) {
592 for (i
= 0; i
< cur_key
->length
; i
++) {
593 /* Lookup using the previous key32 */
599 (wmem_tree_t
*)(*helper
)(lookup_tree
, lookup_key32
);
604 lookup_key32
= cur_key
->key
[i
];
608 /* Assert if we didn't get any valid keys */
609 g_assert(lookup_tree
);
611 return (*helper
)(lookup_tree
, lookup_key32
);
615 wmem_tree_lookup32_array(wmem_tree_t
*tree
, wmem_tree_key_t
*key
)
617 return wmem_tree_lookup32_array_helper(tree
, key
, wmem_tree_lookup32
);
621 wmem_tree_lookup32_array_le(wmem_tree_t
*tree
, wmem_tree_key_t
*key
)
623 return wmem_tree_lookup32_array_helper(tree
, key
, wmem_tree_lookup32_le
);
627 wmem_tree_foreach_nodes(wmem_tree_node_t
* node
, wmem_foreach_func callback
,
630 gboolean stop_traverse
= FALSE
;
637 if (wmem_tree_foreach_nodes(node
->left
, callback
, user_data
)) {
642 if (node
->is_subtree
== TRUE
) {
643 stop_traverse
= wmem_tree_foreach((wmem_tree_t
*)node
->data
,
644 callback
, user_data
);
646 stop_traverse
= callback(node
->data
, user_data
);
654 if (wmem_tree_foreach_nodes(node
->right
, callback
, user_data
)) {
663 wmem_tree_foreach(wmem_tree_t
* tree
, wmem_foreach_func callback
,
669 return wmem_tree_foreach_nodes(tree
->root
, callback
, user_data
);
672 static void wmem_print_subtree(wmem_tree_t
*tree
, guint32 level
);
675 wmem_tree_print_nodes(const char *prefix
, wmem_tree_node_t
*node
, guint32 level
)
682 for (i
=0; i
<level
; i
++) {
686 printf("%sNODE:%p parent:%p left:%p right:%p colour:%s key:%u %s:%p\n",
688 (void *)node
, (void *)node
->parent
,
689 (void *)node
->left
, (void *)node
->right
,
690 node
->color
?"Black":"Red", node
->key32
,
691 node
->is_subtree
?"tree":"data", node
->data
);
693 wmem_tree_print_nodes("L-", node
->left
, level
+1);
695 wmem_tree_print_nodes("R-", node
->right
, level
+1);
697 if (node
->is_subtree
)
698 wmem_print_subtree((wmem_tree_t
*)node
->data
, level
+1);
702 wmem_print_subtree(wmem_tree_t
*tree
, guint32 level
)
709 for (i
=0; i
<level
; i
++) {
713 printf("WMEM tree:%p root:%p\n", (void *)tree
, (void *)tree
->root
);
715 wmem_tree_print_nodes("Root-", tree
->root
, level
);
720 wmem_print_tree(wmem_tree_t
*tree
)
722 wmem_print_subtree(tree
, 0);
726 * Editor modelines - http://www.wireshark.org/tools/modelines.html
731 * indent-tabs-mode: nil
734 * vi: set shiftwidth=4 tabstop=8 expandtab:
735 * :indentSize=4:tabSize=8:noTabs=true: