diff --git a/include/libbase/avltree.h b/include/libbase/avltree.h index f390d45..c946a50 100644 --- a/include/libbase/avltree.h +++ b/include/libbase/avltree.h @@ -122,6 +122,16 @@ bool bs_avltree_insert(bs_avltree_t *tree_ptr, bs_avltree_node_t *bs_avltree_delete(bs_avltree_t *tree_ptr, const void *key_ptr); +/** + * Removes and destroys each node of the tree. + * + * This will step through each node, and calls the node's registered destructor, + * if provided. + * + * @param tree_ptr + */ +void bs_avltree_flush(bs_avltree_t *tree_ptr); + /** Returns the minimum node of the tree. */ bs_avltree_node_t *bs_avltree_min(bs_avltree_t *tree_ptr); diff --git a/src/avltree.c b/src/avltree.c index 9118378..d1590cc 100644 --- a/src/avltree.c +++ b/src/avltree.c @@ -40,7 +40,6 @@ struct _bs_avltree_t { bs_avltree_node_destroy_t destroy; }; -static void bs_avltree_flush(bs_avltree_t *tree_ptr); static void bs_avltree_node_replace(bs_avltree_t *tree_ptr, bs_avltree_node_t *old_node_ptr, bs_avltree_node_t *new_node_ptr); @@ -220,6 +219,51 @@ bs_avltree_node_t *bs_avltree_delete(bs_avltree_t *tree_ptr, return node_ptr; } +/* ------------------------------------------------------------------------- */ +void bs_avltree_flush(bs_avltree_t *tree_ptr) +{ + bs_avltree_node_t *node_ptr; + bs_avltree_node_t *parent_ptr; + + node_ptr = tree_ptr->root_ptr; + // Already mark the tree as inaccessible. + tree_ptr->root_ptr = NULL; + while (NULL != node_ptr) { + + /* walk tree downwards as far as possible */ + if (NULL != node_ptr->left_ptr) { + node_ptr = node_ptr->left_ptr; + continue; + } + if (NULL != node_ptr->right_ptr) { + node_ptr = node_ptr->right_ptr; + continue; + } + + /* store parent node, then clear bottom-most node */ + parent_ptr = node_ptr->parent_ptr; + *node_ptr = (bs_avltree_node_t){}; + if (NULL != tree_ptr->destroy) { + tree_ptr->destroy(node_ptr); + } + tree_ptr->nodes--; + + /* if the parent is NULL, we just flushed the root node. all done. */ + if (NULL == parent_ptr) break; + + /* in parent: mark the just-deleted node as gone */ + if (parent_ptr->left_ptr == node_ptr) { + parent_ptr->left_ptr = NULL; + } else { + parent_ptr->right_ptr = NULL; + } + + node_ptr = parent_ptr; + } + + BS_ASSERT(0 == tree_ptr->nodes); +} + /* ------------------------------------------------------------------------- */ size_t bs_avltree_size(const bs_avltree_t *tree_ptr) { @@ -316,52 +360,6 @@ int bs_avltree_cmp_ptr(const void *node_key_ptr, /* == Local methods ======================================================== */ -/* ------------------------------------------------------------------------- */ -/** Will destroy (if given) each of the nodes. */ -void bs_avltree_flush(bs_avltree_t *tree_ptr) -{ - bs_avltree_node_t *node_ptr; - bs_avltree_node_t *parent_ptr; - - node_ptr = tree_ptr->root_ptr; - // Already mark the tree as inaccessible. - tree_ptr->root_ptr = NULL; - while (NULL != node_ptr) { - - /* walk tree downwards as far as possible */ - if (NULL != node_ptr->left_ptr) { - node_ptr = node_ptr->left_ptr; - continue; - } - if (NULL != node_ptr->right_ptr) { - node_ptr = node_ptr->right_ptr; - continue; - } - - /* store parent node, then clear bottom-most node */ - parent_ptr = node_ptr->parent_ptr; - *node_ptr = (bs_avltree_node_t){}; - if (NULL != tree_ptr->destroy) { - tree_ptr->destroy(node_ptr); - } - tree_ptr->nodes--; - - /* if the parent is NULL, we just flushed the root node. all done. */ - if (NULL == parent_ptr) break; - - /* in parent: mark the just-deleted node as gone */ - if (parent_ptr->left_ptr == node_ptr) { - parent_ptr->left_ptr = NULL; - } else { - parent_ptr->right_ptr = NULL; - } - - node_ptr = parent_ptr; - } - - BS_ASSERT(0 == tree_ptr->nodes); -} - /* ------------------------------------------------------------------------- */ /** * Replaces the node at |old_node_ptr| with |new_node_ptr| in the |tree_ptr|.