Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions include/libbase/avltree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
92 changes: 45 additions & 47 deletions src/avltree.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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|.
Expand Down
Loading