2022-05-11 13:04:34 +03:00
/*
2007-07-24 12:51:13 +04:00
a talloc based red - black tree
Copyright ( C ) Ronnie Sahlberg 2007
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2022-05-11 13:04:34 +03:00
2007-07-24 12:51:13 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2022-05-11 13:04:34 +03:00
2007-07-24 12:51:13 +04:00
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
2015-10-26 08:50:46 +03:00
# include "replace.h"
# include <talloc.h>
# include "lib/util/debug.h"
2015-11-11 07:19:17 +03:00
# include "common/logging.h"
# include "common/rb_tree.h"
2007-07-24 12:51:13 +04:00
# define NO_MEMORY_FATAL(p) do { if (!(p)) { \
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_CRIT , ( " Out of memory for %s at %s \n " , # p , __location__ ) ) ; \
2007-07-24 12:51:13 +04:00
exit ( 10 ) ; \
} } while ( 0 )
2022-05-11 13:04:34 +03:00
static void
2007-08-09 08:08:59 +04:00
tree_destructor_traverse_node ( TALLOC_CTX * mem_ctx , trbt_node_t * node )
{
talloc_set_destructor ( node , NULL ) ;
if ( node - > left ) {
tree_destructor_traverse_node ( mem_ctx , node - > left ) ;
}
if ( node - > right ) {
tree_destructor_traverse_node ( mem_ctx , node - > right ) ;
}
talloc_steal ( mem_ctx , node ) ;
}
/*
destroy a tree and remove all its nodes
*/
static int tree_destructor ( trbt_tree_t * tree )
{
TALLOC_CTX * tmp_ctx ;
trbt_node_t * node ;
if ( tree = = NULL ) {
return 0 ;
}
node = tree - > root ;
if ( node = = NULL ) {
return 0 ;
}
/* traverse the tree and remove the node destructor and steal
the node to the temporary context .
2015-07-27 00:02:57 +03:00
we don ' t want to use the existing destructor for the node
2007-08-09 08:08:59 +04:00
since that will remove the nodes one by one from the tree .
2015-07-27 00:02:57 +03:00
since the entire tree will be completely destroyed we don ' t care
2007-08-09 08:08:59 +04:00
if it is inconsistent or unbalanced while freeing the
individual nodes
*/
tmp_ctx = talloc_new ( NULL ) ;
tree_destructor_traverse_node ( tmp_ctx , node ) ;
talloc_free ( tmp_ctx ) ;
return 0 ;
}
/* create a red black tree */
2007-07-24 12:51:13 +04:00
trbt_tree_t *
2007-08-09 08:08:59 +04:00
trbt_create ( TALLOC_CTX * memctx , uint32_t flags )
2007-07-24 12:51:13 +04:00
{
trbt_tree_t * tree ;
tree = talloc_zero ( memctx , trbt_tree_t ) ;
NO_MEMORY_FATAL ( tree ) ;
2007-08-09 08:08:59 +04:00
/* If the tree is freed, we must walk over all entries and steal the
node from the stored data pointer and release the node .
2022-05-11 13:04:34 +03:00
Note , when we free the tree we only free the tree and not any of
2007-08-09 08:08:59 +04:00
the data stored in the tree .
*/
talloc_set_destructor ( tree , tree_destructor ) ;
tree - > flags = flags ;
2007-07-24 12:51:13 +04:00
return tree ;
}
static inline trbt_node_t *
trbt_parent ( trbt_node_t * node )
{
return node - > parent ;
}
static inline trbt_node_t *
trbt_grandparent ( trbt_node_t * node )
{
trbt_node_t * parent ;
parent = trbt_parent ( node ) ;
if ( parent ) {
return parent - > parent ;
}
return NULL ;
}
static inline trbt_node_t *
trbt_uncle ( trbt_node_t * node )
{
trbt_node_t * parent , * grandparent ;
parent = trbt_parent ( node ) ;
if ( ! parent ) {
return NULL ;
}
grandparent = trbt_parent ( parent ) ;
if ( ! grandparent ) {
return NULL ;
}
if ( parent = = grandparent - > left ) {
return grandparent - > right ;
}
return grandparent - > left ;
}
static inline void trbt_insert_case1 ( trbt_tree_t * tree , trbt_node_t * node ) ;
static inline void trbt_insert_case2 ( trbt_tree_t * tree , trbt_node_t * node ) ;
static inline void
trbt_rotate_left ( trbt_node_t * node )
{
trbt_tree_t * tree = node - > tree ;
if ( node - > parent ) {
if ( node - > parent - > left = = node ) {
node - > parent - > left = node - > right ;
} else {
node - > parent - > right = node - > right ;
}
} else {
2007-08-08 05:21:18 +04:00
tree - > root = node - > right ;
2007-07-24 12:51:13 +04:00
}
node - > right - > parent = node - > parent ;
node - > parent = node - > right ;
node - > right = node - > right - > left ;
if ( node - > right ) {
node - > right - > parent = node ;
}
node - > parent - > left = node ;
}
static inline void
trbt_rotate_right ( trbt_node_t * node )
{
trbt_tree_t * tree = node - > tree ;
if ( node - > parent ) {
if ( node - > parent - > left = = node ) {
node - > parent - > left = node - > left ;
} else {
node - > parent - > right = node - > left ;
}
} else {
2007-08-08 05:21:18 +04:00
tree - > root = node - > left ;
2007-07-24 12:51:13 +04:00
}
node - > left - > parent = node - > parent ;
node - > parent = node - > left ;
node - > left = node - > left - > right ;
if ( node - > left ) {
node - > left - > parent = node ;
}
node - > parent - > right = node ;
}
2007-07-25 11:53:55 +04:00
/* NULL nodes are black by definition */
2007-07-26 01:21:32 +04:00
static inline int trbt_get_color ( trbt_node_t * node )
2007-07-25 11:53:55 +04:00
{
if ( node = = NULL ) {
return TRBT_BLACK ;
}
return node - > rb_color ;
}
2007-07-26 01:21:32 +04:00
static inline int trbt_get_color_left ( trbt_node_t * node )
{
if ( node = = NULL ) {
return TRBT_BLACK ;
}
if ( node - > left = = NULL ) {
return TRBT_BLACK ;
}
return node - > left - > rb_color ;
}
static inline int trbt_get_color_right ( trbt_node_t * node )
{
if ( node = = NULL ) {
return TRBT_BLACK ;
}
if ( node - > right = = NULL ) {
return TRBT_BLACK ;
}
return node - > right - > rb_color ;
}
/* setting a NULL node to black is a nop */
static inline void trbt_set_color ( trbt_node_t * node , int color )
{
2016-08-05 09:39:50 +03:00
if ( node = = NULL ) {
2007-07-26 01:21:32 +04:00
return ;
}
node - > rb_color = color ;
}
static inline void trbt_set_color_left ( trbt_node_t * node , int color )
{
2016-08-05 09:38:45 +03:00
if ( node = = NULL | | node - > left = = NULL ) {
2007-07-26 01:21:32 +04:00
return ;
}
node - > left - > rb_color = color ;
}
static inline void trbt_set_color_right ( trbt_node_t * node , int color )
{
2016-08-05 09:37:00 +03:00
if ( node = = NULL | | node - > right = = NULL ) {
2007-07-26 01:21:32 +04:00
return ;
}
node - > right - > rb_color = color ;
}
2007-07-25 11:53:55 +04:00
2007-07-24 12:51:13 +04:00
static inline void
trbt_insert_case5 ( trbt_tree_t * tree , trbt_node_t * node )
{
trbt_node_t * grandparent ;
trbt_node_t * parent ;
parent = trbt_parent ( node ) ;
grandparent = trbt_parent ( parent ) ;
parent - > rb_color = TRBT_BLACK ;
grandparent - > rb_color = TRBT_RED ;
if ( ( node = = parent - > left ) & & ( parent = = grandparent - > left ) ) {
trbt_rotate_right ( grandparent ) ;
} else {
trbt_rotate_left ( grandparent ) ;
}
}
static inline void
trbt_insert_case4 ( trbt_tree_t * tree , trbt_node_t * node )
{
trbt_node_t * grandparent ;
trbt_node_t * parent ;
parent = trbt_parent ( node ) ;
grandparent = trbt_parent ( parent ) ;
if ( ! grandparent ) {
return ;
}
if ( ( node = = parent - > right ) & & ( parent = = grandparent - > left ) ) {
trbt_rotate_left ( parent ) ;
node = node - > left ;
} else if ( ( node = = parent - > left ) & & ( parent = = grandparent - > right ) ) {
trbt_rotate_right ( parent ) ;
node = node - > right ;
}
trbt_insert_case5 ( tree , node ) ;
}
static inline void
trbt_insert_case3 ( trbt_tree_t * tree , trbt_node_t * node )
{
trbt_node_t * grandparent ;
trbt_node_t * parent ;
trbt_node_t * uncle ;
uncle = trbt_uncle ( node ) ;
if ( uncle & & ( uncle - > rb_color = = TRBT_RED ) ) {
parent = trbt_parent ( node ) ;
parent - > rb_color = TRBT_BLACK ;
uncle - > rb_color = TRBT_BLACK ;
grandparent = trbt_grandparent ( node ) ;
grandparent - > rb_color = TRBT_RED ;
trbt_insert_case1 ( tree , grandparent ) ;
} else {
trbt_insert_case4 ( tree , node ) ;
}
}
static inline void
trbt_insert_case2 ( trbt_tree_t * tree , trbt_node_t * node )
{
trbt_node_t * parent ;
parent = trbt_parent ( node ) ;
/* parent is always non-NULL here */
if ( parent - > rb_color = = TRBT_BLACK ) {
return ;
}
trbt_insert_case3 ( tree , node ) ;
}
static inline void
trbt_insert_case1 ( trbt_tree_t * tree , trbt_node_t * node )
{
trbt_node_t * parent ;
parent = trbt_parent ( node ) ;
if ( ! parent ) {
node - > rb_color = TRBT_BLACK ;
return ;
}
trbt_insert_case2 ( tree , node ) ;
}
static inline trbt_node_t *
trbt_sibling ( trbt_node_t * node )
{
trbt_node_t * parent ;
parent = trbt_parent ( node ) ;
if ( ! parent ) {
return NULL ;
}
if ( node = = parent - > left ) {
return parent - > right ;
} else {
return parent - > left ;
}
}
static inline void
trbt_delete_case6 ( trbt_node_t * node )
{
trbt_node_t * sibling , * parent ;
sibling = trbt_sibling ( node ) ;
parent = trbt_parent ( node ) ;
2007-07-26 01:21:32 +04:00
trbt_set_color ( sibling , parent - > rb_color ) ;
trbt_set_color ( parent , TRBT_BLACK ) ;
2007-07-24 12:51:13 +04:00
if ( node = = parent - > left ) {
2007-07-26 01:21:32 +04:00
trbt_set_color_right ( sibling , TRBT_BLACK ) ;
2007-07-24 12:51:13 +04:00
trbt_rotate_left ( parent ) ;
} else {
2007-07-26 01:21:32 +04:00
trbt_set_color_left ( sibling , TRBT_BLACK ) ;
2007-07-24 12:51:13 +04:00
trbt_rotate_right ( parent ) ;
}
}
static inline void
trbt_delete_case5 ( trbt_node_t * node )
{
trbt_node_t * parent , * sibling ;
parent = trbt_parent ( node ) ;
sibling = trbt_sibling ( node ) ;
if ( ( node = = parent - > left )
2007-07-26 01:21:32 +04:00
& & ( trbt_get_color ( sibling ) = = TRBT_BLACK )
& & ( trbt_get_color_left ( sibling ) = = TRBT_RED )
& & ( trbt_get_color_right ( sibling ) = = TRBT_BLACK ) ) {
trbt_set_color ( sibling , TRBT_RED ) ;
trbt_set_color_left ( sibling , TRBT_BLACK ) ;
2007-07-24 12:51:13 +04:00
trbt_rotate_right ( sibling ) ;
trbt_delete_case6 ( node ) ;
return ;
2022-05-11 13:04:34 +03:00
}
2007-07-24 12:51:13 +04:00
if ( ( node = = parent - > right )
2007-07-26 01:21:32 +04:00
& & ( trbt_get_color ( sibling ) = = TRBT_BLACK )
& & ( trbt_get_color_right ( sibling ) = = TRBT_RED )
& & ( trbt_get_color_left ( sibling ) = = TRBT_BLACK ) ) {
trbt_set_color ( sibling , TRBT_RED ) ;
trbt_set_color_right ( sibling , TRBT_BLACK ) ;
2007-07-24 12:51:13 +04:00
trbt_rotate_left ( sibling ) ;
trbt_delete_case6 ( node ) ;
return ;
}
trbt_delete_case6 ( node ) ;
}
static inline void
trbt_delete_case4 ( trbt_node_t * node )
{
trbt_node_t * sibling ;
sibling = trbt_sibling ( node ) ;
2007-07-26 01:21:32 +04:00
if ( ( trbt_get_color ( node - > parent ) = = TRBT_RED )
& & ( trbt_get_color ( sibling ) = = TRBT_BLACK )
& & ( trbt_get_color_left ( sibling ) = = TRBT_BLACK )
& & ( trbt_get_color_right ( sibling ) = = TRBT_BLACK ) ) {
trbt_set_color ( sibling , TRBT_RED ) ;
trbt_set_color ( node - > parent , TRBT_BLACK ) ;
2007-07-24 12:51:13 +04:00
} else {
trbt_delete_case5 ( node ) ;
}
}
static void trbt_delete_case1 ( trbt_node_t * node ) ;
static inline void
trbt_delete_case3 ( trbt_node_t * node )
{
trbt_node_t * sibling ;
sibling = trbt_sibling ( node ) ;
2007-07-26 01:21:32 +04:00
if ( ( trbt_get_color ( node - > parent ) = = TRBT_BLACK )
& & ( trbt_get_color ( sibling ) = = TRBT_BLACK )
& & ( trbt_get_color_left ( sibling ) = = TRBT_BLACK )
& & ( trbt_get_color_right ( sibling ) = = TRBT_BLACK ) ) {
trbt_set_color ( sibling , TRBT_RED ) ;
2007-07-24 12:51:13 +04:00
trbt_delete_case1 ( node - > parent ) ;
} else {
trbt_delete_case4 ( node ) ;
}
}
2022-05-11 13:04:34 +03:00
2007-07-24 12:51:13 +04:00
static inline void
trbt_delete_case2 ( trbt_node_t * node )
{
trbt_node_t * sibling ;
sibling = trbt_sibling ( node ) ;
2007-07-26 01:21:32 +04:00
if ( trbt_get_color ( sibling ) = = TRBT_RED ) {
trbt_set_color ( node - > parent , TRBT_RED ) ;
trbt_set_color ( sibling , TRBT_BLACK ) ;
2007-07-24 12:51:13 +04:00
if ( node = = node - > parent - > left ) {
trbt_rotate_left ( node - > parent ) ;
} else {
trbt_rotate_right ( node - > parent ) ;
}
}
trbt_delete_case3 ( node ) ;
2022-05-11 13:04:34 +03:00
}
2007-07-24 12:51:13 +04:00
static void
trbt_delete_case1 ( trbt_node_t * node )
{
if ( ! node - > parent ) {
return ;
} else {
trbt_delete_case2 ( node ) ;
}
}
static void
2012-05-17 10:08:37 +04:00
delete_node ( trbt_node_t * node , bool from_destructor )
2007-07-24 12:51:13 +04:00
{
2007-07-26 01:21:32 +04:00
trbt_node_t * parent , * child , dc ;
2007-08-09 08:08:59 +04:00
trbt_node_t * temp = NULL ;
2007-07-24 12:51:13 +04:00
2007-07-30 03:09:34 +04:00
/* This node has two child nodes, then just copy the content
2022-05-11 13:04:34 +03:00
from the next smaller node with this node and delete the
2007-07-30 03:09:34 +04:00
predecessor instead .
The predecessor is guaranteed to have at most one child
node since its right arm must be NULL
2023-03-22 11:24:04 +03:00
( It must be NULL since we are its successor and we are above
2007-07-30 03:09:34 +04:00
it in the tree )
*/
2007-07-24 12:51:13 +04:00
if ( node - > left ! = NULL & & node - > right ! = NULL ) {
/* This node has two children, just copy the data */
/* find the predecessor */
2007-08-09 08:08:59 +04:00
temp = node - > left ;
2007-07-24 12:51:13 +04:00
while ( temp - > right ! = NULL ) {
temp = temp - > right ;
}
/* swap the predecessor data and key with the node to
be deleted .
*/
node - > key32 = temp - > key32 ;
2007-08-09 08:08:59 +04:00
node - > data = temp - > data ;
/* now we let node hang off the new data */
talloc_steal ( node - > data , node ) ;
2022-05-11 13:04:34 +03:00
2007-07-24 12:51:13 +04:00
temp - > data = NULL ;
temp - > key32 = - 1 ;
/* then delete the temp node.
2022-05-11 13:04:34 +03:00
this node is guaranteed to have at least one leaf
2007-08-09 08:08:59 +04:00
child */
delete_node ( temp , from_destructor ) ;
goto finished ;
2007-07-24 12:51:13 +04:00
}
2007-07-26 01:21:32 +04:00
2007-07-24 12:51:13 +04:00
/* There is at most one child to this node to be deleted */
child = node - > left ;
if ( node - > right ) {
child = node - > right ;
}
2007-07-30 03:09:34 +04:00
/* If the node to be deleted did not have any child at all we
create a temporary dummy node for the child and mark it black .
Once the delete of the node is finished , we remove this dummy
node , which is simple to do since it is guaranteed that it will
still not have any children after the delete operation .
2015-07-27 00:02:57 +03:00
This is because we don ' t represent the leaf - nodes as actual nodes
2007-07-30 03:09:34 +04:00
in this implementation .
*/
2007-07-26 01:21:32 +04:00
if ( ! child ) {
child = & dc ;
child - > tree = node - > tree ;
child - > left = NULL ;
child - > right = NULL ;
child - > rb_color = TRBT_BLACK ;
child - > data = NULL ;
}
2007-07-24 12:51:13 +04:00
/* replace node with child */
2007-07-26 01:21:32 +04:00
parent = trbt_parent ( node ) ;
2007-07-24 12:51:13 +04:00
if ( parent ) {
if ( parent - > left = = node ) {
parent - > left = child ;
} else {
parent - > right = child ;
}
2007-07-30 03:09:34 +04:00
} else {
2007-08-08 05:21:18 +04:00
node - > tree - > root = child ;
2007-07-24 12:51:13 +04:00
}
2007-07-26 01:21:32 +04:00
child - > parent = node - > parent ;
2007-07-24 12:51:13 +04:00
2007-07-30 03:09:34 +04:00
2007-07-26 01:21:32 +04:00
if ( node - > rb_color = = TRBT_BLACK ) {
if ( trbt_get_color ( child ) = = TRBT_RED ) {
child - > rb_color = TRBT_BLACK ;
} else {
trbt_delete_case1 ( child ) ;
}
}
2007-07-24 12:51:13 +04:00
2022-05-11 13:04:34 +03:00
/* If we had to create a temporary dummy node to represent a black
2007-07-30 03:09:34 +04:00
leaf child we now has to delete it .
This is simple since this dummy node originally had no children
2022-05-11 13:04:34 +03:00
and we are guaranteed that it will also not have any children
after the node has been deleted and any possible rotations
2017-02-17 22:46:28 +03:00
have occurred .
2007-07-30 03:09:34 +04:00
The only special case is if this was the last node of the tree
in which case we have to reset the root to NULL as well .
Othervise it is enough to just unlink the child from its new
parent .
*/
2007-07-26 01:21:32 +04:00
if ( child = = & dc ) {
2007-07-30 03:09:34 +04:00
if ( child - > parent = = NULL ) {
2007-08-08 05:21:18 +04:00
node - > tree - > root = NULL ;
2007-07-30 03:09:34 +04:00
} else if ( child = = child - > parent - > left ) {
2007-07-26 01:21:32 +04:00
child - > parent - > left = NULL ;
} else {
child - > parent - > right = NULL ;
2007-07-24 12:51:13 +04:00
}
}
2007-07-26 01:21:32 +04:00
2007-08-09 08:08:59 +04:00
finished :
if ( ! from_destructor ) {
talloc_free ( node ) ;
}
/* if we came from a destructor and temp!=NULL this means we
did the node - swap but now the tree still contains the old
node which was freed in the destructor . Not good .
*/
if ( from_destructor & & temp ) {
temp - > key32 = node - > key32 ;
temp - > rb_color = node - > rb_color ;
temp - > data = node - > data ;
talloc_steal ( temp - > data , temp ) ;
temp - > parent = node - > parent ;
if ( temp - > parent ) {
if ( temp - > parent - > left = = node ) {
temp - > parent - > left = temp ;
} else {
temp - > parent - > right = temp ;
}
}
temp - > left = node - > left ;
if ( temp - > left ) {
temp - > left - > parent = temp ;
}
temp - > right = node - > right ;
if ( temp - > right ) {
temp - > right - > parent = temp ;
}
if ( temp - > tree - > root = = node ) {
temp - > tree - > root = temp ;
}
}
if ( ( node - > tree - > flags & TRBT_AUTOFREE )
& & ( node - > tree - > root = = NULL ) ) {
talloc_free ( node - > tree ) ;
}
2007-07-24 12:51:13 +04:00
return ;
}
2007-08-09 08:08:59 +04:00
/*
destroy a node and remove it from its tree
*/
static int node_destructor ( trbt_node_t * node )
{
2012-05-17 10:08:37 +04:00
delete_node ( node , true ) ;
2007-08-09 08:08:59 +04:00
return 0 ;
}
2007-07-24 12:51:13 +04:00
static inline trbt_node_t *
trbt_create_node ( trbt_tree_t * tree , trbt_node_t * parent , uint32_t key , void * data )
{
trbt_node_t * node ;
node = talloc_zero ( tree , trbt_node_t ) ;
NO_MEMORY_FATAL ( node ) ;
node - > tree = tree ;
node - > rb_color = TRBT_BLACK ;
node - > parent = parent ;
node - > left = NULL ;
node - > right = NULL ;
node - > key32 = key ;
2007-08-09 08:08:59 +04:00
node - > data = data ;
/* let this node hang off data so that it is removed when
data is freed
*/
talloc_steal ( data , node ) ;
talloc_set_destructor ( node , node_destructor ) ;
2007-07-24 12:51:13 +04:00
return node ;
}
2022-05-11 13:04:34 +03:00
/* insert a new node in the tree.
if there is already a node with a matching key in the tree
2007-08-08 02:20:46 +04:00
we replace it with the new data and return a pointer to the old data
in case the caller wants to take any special action
2007-07-24 12:51:13 +04:00
*/
2007-08-08 02:20:46 +04:00
void *
2007-07-24 12:51:13 +04:00
trbt_insert32 ( trbt_tree_t * tree , uint32_t key , void * data )
{
trbt_node_t * node ;
2007-08-08 05:21:18 +04:00
node = tree - > root ;
2007-07-24 12:51:13 +04:00
/* is this the first node ?*/
if ( ! node ) {
node = trbt_create_node ( tree , NULL , key , data ) ;
2007-08-08 05:21:18 +04:00
tree - > root = node ;
2007-08-08 02:20:46 +04:00
return NULL ;
2007-07-24 12:51:13 +04:00
}
/* it was not the new root so walk the tree until we find where to
* insert this new leaf .
*/
while ( 1 ) {
2022-05-11 13:04:34 +03:00
/* this node already exists, replace data and return the
2007-08-08 02:20:46 +04:00
old data
*/
2007-07-24 12:51:13 +04:00
if ( key = = node - > key32 ) {
2007-08-08 02:20:46 +04:00
void * old_data ;
old_data = node - > data ;
2007-08-09 08:08:59 +04:00
node - > data = data ;
/* Let the node now be owned by the new data
so the node is freed when the enw data is released
*/
talloc_steal ( node - > data , node ) ;
2007-08-08 02:20:46 +04:00
return old_data ;
2007-07-24 12:51:13 +04:00
}
if ( key < node - > key32 ) {
if ( ! node - > left ) {
/* new node to the left */
trbt_node_t * new_node ;
new_node = trbt_create_node ( tree , node , key , data ) ;
node - > left = new_node ;
node = new_node ;
break ;
}
node = node - > left ;
continue ;
}
if ( key > node - > key32 ) {
if ( ! node - > right ) {
/* new node to the right */
trbt_node_t * new_node ;
new_node = trbt_create_node ( tree , node , key , data ) ;
node - > right = new_node ;
node = new_node ;
break ;
}
node = node - > right ;
continue ;
}
}
/* node will now point to the newly created node */
node - > rb_color = TRBT_RED ;
trbt_insert_case1 ( tree , node ) ;
2007-08-08 02:20:46 +04:00
return NULL ;
2007-07-24 12:51:13 +04:00
}
void *
trbt_lookup32 ( trbt_tree_t * tree , uint32_t key )
{
trbt_node_t * node ;
2007-08-08 05:21:18 +04:00
node = tree - > root ;
2007-07-24 12:51:13 +04:00
while ( node ) {
if ( key = = node - > key32 ) {
return node - > data ;
}
if ( key < node - > key32 ) {
node = node - > left ;
continue ;
}
if ( key > node - > key32 ) {
node = node - > right ;
continue ;
}
}
return NULL ;
}
2007-08-09 08:08:59 +04:00
/* This deletes a node from the tree.
Note that this does not release the data that the node points to
*/
2022-05-11 13:04:34 +03:00
void
2007-07-24 12:51:13 +04:00
trbt_delete32 ( trbt_tree_t * tree , uint32_t key )
{
trbt_node_t * node ;
2007-08-08 05:21:18 +04:00
node = tree - > root ;
2007-07-24 12:51:13 +04:00
while ( node ) {
if ( key = = node - > key32 ) {
2012-05-17 10:08:37 +04:00
delete_node ( node , false ) ;
2007-07-24 12:51:13 +04:00
return ;
}
if ( key < node - > key32 ) {
node = node - > left ;
continue ;
}
if ( key > node - > key32 ) {
node = node - > right ;
continue ;
}
}
}
2022-05-11 13:04:34 +03:00
void
2007-08-08 05:21:18 +04:00
trbt_insert32_callback ( trbt_tree_t * tree , uint32_t key , void * ( * callback ) ( void * param , void * data ) , void * param )
{
trbt_node_t * node ;
node = tree - > root ;
/* is this the first node ?*/
if ( ! node ) {
2022-05-11 13:04:34 +03:00
node = trbt_create_node ( tree , NULL , key ,
2007-08-08 05:21:18 +04:00
callback ( param , NULL ) ) ;
tree - > root = node ;
return ;
}
/* it was not the new root so walk the tree until we find where to
* insert this new leaf .
*/
while ( 1 ) {
2022-05-11 13:04:34 +03:00
/* this node already exists, replace it
2007-08-08 05:21:18 +04:00
*/
if ( key = = node - > key32 ) {
2007-08-09 08:08:59 +04:00
node - > data = callback ( param , node - > data ) ;
2022-05-11 13:04:34 +03:00
talloc_steal ( node - > data , node ) ;
2007-08-08 05:21:18 +04:00
return ;
}
if ( key < node - > key32 ) {
if ( ! node - > left ) {
/* new node to the left */
trbt_node_t * new_node ;
new_node = trbt_create_node ( tree , node , key ,
callback ( param , NULL ) ) ;
node - > left = new_node ;
node = new_node ;
break ;
}
node = node - > left ;
continue ;
}
if ( key > node - > key32 ) {
if ( ! node - > right ) {
/* new node to the right */
trbt_node_t * new_node ;
new_node = trbt_create_node ( tree , node , key ,
callback ( param , NULL ) ) ;
node - > right = new_node ;
node = new_node ;
break ;
}
node = node - > right ;
continue ;
}
}
/* node will now point to the newly created node */
node - > rb_color = TRBT_RED ;
trbt_insert_case1 ( tree , node ) ;
return ;
}
2007-08-08 06:30:12 +04:00
struct trbt_array_param {
void * ( * callback ) ( void * param , void * data ) ;
void * param ;
uint32_t keylen ;
uint32_t * key ;
trbt_tree_t * tree ;
} ;
static void * array_insert_callback ( void * p , void * data )
{
struct trbt_array_param * param = ( struct trbt_array_param * ) p ;
trbt_tree_t * tree = NULL ;
2022-05-11 13:04:34 +03:00
/* if keylen has reached 0 we are done and can call the users
2007-08-08 06:30:12 +04:00
callback function with the users parameters
*/
if ( param - > keylen = = 0 ) {
return param - > callback ( param - > param , data ) ;
}
/* keylen is not zero yes so we must create/process more subtrees */
/* if data is NULL this means we did not yet have a subtree here
and we must create one .
*/
if ( data = = NULL ) {
2007-08-09 08:08:59 +04:00
/* create a new subtree and hang it off our current tree
set it to autofree so that the tree is freed when
the last node in it has been released .
*/
tree = trbt_create ( param - > tree , TRBT_AUTOFREE ) ;
2007-08-08 06:30:12 +04:00
} else {
/* we already have a subtree for this path */
tree = ( trbt_tree_t * ) data ;
}
2022-05-11 13:04:34 +03:00
2007-08-08 06:30:12 +04:00
trbt_insertarray32_callback ( tree , param - > keylen , param - > key , param - > callback , param - > param ) ;
/* now return either the old tree we got in *data or the new tree
we created to our caller so he can update his pointer in his
tree to point to our subtree
*/
return tree ;
}
/* insert into the tree using an array of uint32 as a key */
2022-05-11 13:04:34 +03:00
void
2007-08-08 06:30:12 +04:00
trbt_insertarray32_callback ( trbt_tree_t * tree , uint32_t keylen , uint32_t * key , void * ( * cb ) ( void * param , void * data ) , void * pm )
{
struct trbt_array_param tap ;
/* keylen-1 and key[1] since the call to insert32 will consume the
first part of the key .
*/
tap . callback = cb ;
tap . param = pm ;
tap . keylen = keylen - 1 ;
tap . key = & key [ 1 ] ;
tap . tree = tree ;
trbt_insert32_callback ( tree , key [ 0 ] , array_insert_callback , & tap ) ;
}
/* lookup the tree using an array of uint32 as a key */
void *
trbt_lookuparray32 ( trbt_tree_t * tree , uint32_t keylen , uint32_t * key )
{
/* if keylen is 1 we can do a regular lookup and return this to the
2022-05-11 13:04:34 +03:00
user
2007-08-08 06:30:12 +04:00
*/
if ( keylen = = 1 ) {
return trbt_lookup32 ( tree , key [ 0 ] ) ;
}
/* we need to lookup the next subtree */
tree = trbt_lookup32 ( tree , key [ 0 ] ) ;
if ( tree = = NULL ) {
/* the key does not exist, return NULL */
return NULL ;
}
/* now lookup the next part of the key in our new tree */
return trbt_lookuparray32 ( tree , keylen - 1 , & key [ 1 ] ) ;
}
2007-08-08 07:50:18 +04:00
/* traverse a tree starting at node */
2011-11-02 06:33:28 +04:00
static int
2022-05-11 13:04:34 +03:00
trbt_traversearray32_node ( trbt_node_t * node , uint32_t keylen ,
int ( * callback ) ( void * param , void * data ) ,
2007-08-08 07:50:18 +04:00
void * param )
{
2011-12-22 21:09:36 +04:00
trbt_node_t * left = node - > left ;
trbt_node_t * right = node - > right ;
if ( left ) {
2011-11-02 06:33:28 +04:00
int ret ;
2011-12-22 21:09:36 +04:00
ret = trbt_traversearray32_node ( left , keylen , callback , param ) ;
2011-11-02 06:33:28 +04:00
if ( ret ! = 0 ) {
return ret ;
}
2007-08-08 07:50:18 +04:00
}
/* this is the smallest node in this subtree
if keylen is 0 this means we can just call the callback
otherwise we must pull the next subtree and traverse that one as well
*/
if ( keylen = = 0 ) {
2011-11-02 06:33:28 +04:00
int ret ;
ret = callback ( param , node - > data ) ;
if ( ret ! = 0 ) {
return ret ;
}
2007-08-08 07:50:18 +04:00
} else {
2011-11-02 06:33:28 +04:00
int ret ;
ret = trbt_traversearray32 ( node - > data , keylen , callback , param ) ;
if ( ret ! = 0 ) {
return ret ;
}
2007-08-08 07:50:18 +04:00
}
2011-12-22 21:09:36 +04:00
if ( right ) {
2011-11-02 06:33:28 +04:00
int ret ;
2011-12-22 21:09:36 +04:00
ret = trbt_traversearray32_node ( right , keylen , callback , param ) ;
2011-11-02 06:33:28 +04:00
if ( ret ! = 0 ) {
return ret ;
}
2007-08-08 07:50:18 +04:00
}
2011-11-02 06:33:28 +04:00
return 0 ;
2007-08-08 07:50:18 +04:00
}
2022-05-11 13:04:34 +03:00
2007-08-08 07:50:18 +04:00
/* traverse the tree using an array of uint32 as a key */
2022-05-11 13:04:34 +03:00
int
trbt_traversearray32 ( trbt_tree_t * tree , uint32_t keylen ,
int ( * callback ) ( void * param , void * data ) ,
2007-08-08 07:50:18 +04:00
void * param )
{
trbt_node_t * node ;
if ( tree = = NULL ) {
2011-11-02 06:33:28 +04:00
return 0 ;
2007-08-08 07:50:18 +04:00
}
node = tree - > root ;
if ( node = = NULL ) {
2011-11-02 06:33:28 +04:00
return 0 ;
2007-08-08 07:50:18 +04:00
}
2011-11-02 06:33:28 +04:00
return trbt_traversearray32_node ( node , keylen - 1 , callback , param ) ;
2007-08-08 07:50:18 +04:00
}
2007-08-15 04:57:21 +04:00
/* this function will return the first node in a tree where
the key is an array of uint32_t
*/
void *
trbt_findfirstarray32 ( trbt_tree_t * tree , uint32_t keylen )
{
trbt_node_t * node ;
if ( keylen < 1 ) {
return NULL ;
}
2022-05-11 13:04:34 +03:00
2007-08-15 04:57:21 +04:00
if ( tree = = NULL ) {
return NULL ;
}
node = tree - > root ;
if ( node = = NULL ) {
return NULL ;
}
while ( node - > left ) {
node = node - > left ;
}
/* we found our node so return the data */
if ( keylen = = 1 ) {
return node - > data ;
}
/* we are still traversing subtrees so find the first node in the
next level of trees
*/
return trbt_findfirstarray32 ( node - > data , keylen - 1 ) ;
}
2019-05-23 10:49:26 +03:00
# ifdef TEST_RB_TREE
2007-07-24 12:51:13 +04:00
static void printtree ( trbt_node_t * node , int levels )
{
int i ;
if ( node = = NULL ) return ;
printtree ( node - > left , levels + 1 ) ;
for ( i = 0 ; i < levels ; i + + ) printf ( " " ) ;
2011-11-02 06:33:28 +04:00
printf ( " key:%d COLOR:%s (node:%p parent:%p left:%p right:%p) \n " , node - > key32 , node - > rb_color = = TRBT_BLACK ? " BLACK " : " RED " , node , node - > parent , node - > left , node - > right ) ;
2007-07-24 12:51:13 +04:00
printtree ( node - > right , levels + 1 ) ;
printf ( " \n " ) ;
}
void print_tree ( trbt_tree_t * tree )
{
2007-08-09 08:08:59 +04:00
if ( tree - > root = = NULL ) {
2007-07-25 11:53:55 +04:00
printf ( " tree is empty \n " ) ;
return ;
}
printf ( " --- \n " ) ;
2007-08-09 08:08:59 +04:00
printtree ( tree - > root - > left , 1 ) ;
2011-11-02 06:33:28 +04:00
printf ( " root node key:%d COLOR:%s (node:%p left:%p right:%p) \n " , tree - > root - > key32 , tree - > root - > rb_color = = TRBT_BLACK ? " BLACK " : " RED " , tree - > root , tree - > root - > left , tree - > root - > right ) ;
2007-08-09 08:08:59 +04:00
printtree ( tree - > root - > right , 1 ) ;
2007-07-25 11:53:55 +04:00
printf ( " === \n " ) ;
2007-07-24 12:51:13 +04:00
}
2022-05-11 13:04:34 +03:00
void
2007-07-24 12:51:13 +04:00
test_tree ( void )
{
trbt_tree_t * tree ;
char * str ;
int i , ret ;
2007-07-25 11:53:55 +04:00
int NUM = 15 ;
2007-07-26 01:21:32 +04:00
int cnt = 0 ;
2011-11-02 06:33:28 +04:00
tree = trbt_create ( talloc_new ( NULL ) , 0 ) ;
2007-07-30 03:09:34 +04:00
#if 0
for ( i = 0 ; i < 10 ; i + + ) {
printf ( " adding node %i \n " , i ) ;
trbt_insert32 ( tree , i , NULL ) ;
print_tree ( tree ) ;
}
printf ( " deleting node %i \n " , 3 ) ;
trbt_delete32 ( tree , 3 ) ;
print_tree ( tree ) ;
for ( i = 0 ; i < 10 ; i + + ) {
printf ( " deleting node %i \n " , i ) ;
trbt_delete32 ( tree , i ) ;
print_tree ( tree ) ;
}
exit ( 0 ) ;
# endif
2007-07-26 01:21:32 +04:00
while ( + + cnt ) {
int i ;
printf ( " iteration : %d \n " , cnt ) ;
i = random ( ) % 20 ;
printf ( " adding node %i \n " , i ) ;
trbt_insert32 ( tree , i , NULL ) ;
2007-07-25 11:53:55 +04:00
print_tree ( tree ) ;
2007-07-24 12:51:13 +04:00
2007-07-26 01:21:32 +04:00
i = random ( ) % 20 ;
printf ( " deleting node %i \n " , i ) ;
trbt_delete32 ( tree , i ) ;
print_tree ( tree ) ;
2007-07-24 12:51:13 +04:00
}
2007-07-26 01:21:32 +04:00
2007-07-24 12:51:13 +04:00
}
2019-05-23 10:49:26 +03:00
# endif /* TEST_RB_TREE */