/*
* Copyright (c) 2002-2004 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: tree.c,v 1.12 2005/07/12 23:23:38 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/heap.h"
#include "sm/memops.h"
#include "sm/tree.h"
/*
** XXX need to assign proper error module, look for sm_error_gen()
*/
/*
** SM_TREE_CREATE -- create a new tree
**
** Parameters:
** rpool -- rpool
** limit -- maximum number of entries
** tree_compare -- function to compare keys
**
** Returns:
** tree (NULL on failure)
*/
sm_tree_P
sm_tree_create(sm_rpool_P rpool, uint limit, sm_tree_compare_T tree_compare)
{
sm_tree_P tree;
SM_REQUIRE(tree_compare != NULL);
tree = (sm_tree_P) sm_rpool_zalloc(rpool, sizeof(*tree));
if (tree == NULL)
return NULL;
tree->sm_tree_root = NULL;
tree->sm_tree_rpool = rpool;
tree->sm_tree_compare = tree_compare;
tree->sm_tree_limit = limit;
return tree;
}
/*
** SM_TREE_NODE_ALLOC -- allocate a new node
**
** Parameters:
** tree -- tree
** n -- node to allocate (return value)
** key -- key for insertion
** len -- len of key
** data -- data to insert
**
** Returns:
** ==0 on success
** < 0 error code
*/
sm_ret_T
sm_tree_node_alloc(sm_tree_P tree, sm_tree_node_P *n, sm_tree_key_T key, uint len, sm_tree_data_T data)
{
SM_REQUIRE(n != NULL);
*n = (sm_tree_node_P) sm_rpool_malloc(tree->sm_tree_rpool, sizeof(**n));
if (*n == NULL)
return sm_error_gen(0, SM_ERR_TEMP, ENOMEM);
sm_tree_assign_key((*n)->sm_tree_key, key);
(*n)->sm_tree_key_len = len;
sm_tree_assign_data((*n)->sm_tree_data, data);
(*n)->sm_tree_balance = 0;
(*n)->sm_tree_parent = (*n)->sm_tree_left = (*n)->sm_tree_right = NULL;
return SM_SUCCESS;
}
/*
** SM_TREE_NODE_FREE -- free a new node
**
** Parameters:
** tree -- tree
** n -- node to free
**
** Returns:
** ==0 on success
** < 0 error code
*/
sm_ret_T
sm_tree_node_free(sm_tree_P tree, sm_tree_node_P n)
{
if (n == NULL)
return SM_SUCCESS;
SM_REQUIRE(tree != NULL);
#if PURIFY
if (n->sm_tree_parent != NULL)
{
if (n == n->sm_tree_parent->sm_tree_left)
n->sm_tree_parent->sm_tree_left = NULL;
else if (n == n->sm_tree_parent->sm_tree_right)
n->sm_tree_parent->sm_tree_right = NULL;
}
#endif /* PURIFY */
sm_rpool_free(tree->sm_tree_rpool, n);
return SM_SUCCESS;
}
/*
** SM_TREE_ADD -- add a new node into a tree
**
** Parameters:
** tree -- tree
** key -- key for insertion
** len -- len of key
** data -- data to insert
**
** Returns:
** >=0 on success (difference in height)
** < 0 error code
*/
int
sm_tree_add(sm_tree_P tree, sm_tree_key_T key, uint len, sm_tree_data_T data)
{
SM_REQUIRE(tree != NULL);
/* XXX this doesn't work if we only want to overwrite a node */
if (tree->sm_tree_limit > 0 &&
tree->sm_tree_limit >= tree->sm_tree_used)
return sm_error_gen(0, SM_ERR_TEMP, E2BIG);
++tree->sm_tree_used;
if (tree->sm_tree_root == NULL)
return sm_tree_node_alloc(tree, &(tree->sm_tree_root),
key, len, data);
return sm_tree_insert2(tree, &(tree->sm_tree_root), NULL,
key, len, data);
}
/*
** SM_TREE_RM -- remove a node from a tree
**
** Parameters:
** tree -- tree
** key -- key of node to remove
** len -- len of key
**
** Returns:
** >=0: node removed
** 0: no rebalancing necessary
** 1: rebalancing might be necessary
** -1: node not found
*/
int
sm_tree_rm(sm_tree_P tree, sm_tree_key_T key, uint len)
{
SM_REQUIRE(tree != NULL);
if (tree->sm_tree_root == NULL)
return -1;
return sm_tree_remove2(tree, &(tree->sm_tree_root), NULL, key, len);
}
syntax highlighted by Code2HTML, v. 0.9.1