courier
0.68.2

Go to the source code of this file.
Classes  
struct  node_t 
Defines  
#define  __tsearch tsearch 
#define  __tfind tfind 
#define  __tdelete tdelete 
#define  __twalk twalk 
#define  internal_function 
#define  CHECK_TREE(a) 
Typedefs  
typedef int(*  __compar_fn_t )(const void *, const void *) 
typedef void(*  __action_fn_t )(const void *, VISIT, int) 
typedef struct node_t *  node 
typedef struct node_t *  const_node 
Functions  
static void  maybe_split_for_insert (node *rootp, node *parentp, node *gparentp, int p_r, int gp_r, int mode) 
void *  __tsearch (const void *key, void **vrootp, __compar_fn_t compar) 
void *  __tfind (void *key, void *const *vrootp, __compar_fn_t compar) const 
void *  __tdelete (const void *key, void **vrootp, __compar_fn_t compar) 
static void internal_function  trecurse (const void *vroot, __action_fn_t action, int level) 
void  __twalk (const void *vroot, __action_fn_t action) 
struct node_t 
#define CHECK_TREE  (  a  ) 
#define internal_function 
typedef void(* __action_fn_t)(const void *, VISIT, int) 
typedef int(* __compar_fn_t)(const void *, const void *) 
typedef struct node_t* const_node 
void* __tdelete  (  const void *  key, 
void **  vrootp,  
__compar_fn_t  compar  
) 
Definition at line 365 of file tsearch.c.
{ node p, q, r, retval; int cmp; node *rootp = (node *) vrootp; node root, unchained; /* Stack of nodes so we remember the parents without recursion. It's _very_ unlikely that there are paths longer than 40 nodes. The tree would need to have around 250.000 nodes. */ int stacksize = 100; int sp = 0; node *nodestack[100]; if (rootp == NULL) return NULL; p = *rootp; if (p == NULL) return NULL; CHECK_TREE (p); while ((cmp = (*compar) (key, (*rootp)>key)) != 0) { if (sp == stacksize) abort (); nodestack[sp++] = rootp; p = *rootp; rootp = ((cmp < 0) ? &(*rootp)>left : &(*rootp)>right); if (*rootp == NULL) return NULL; } /* This is bogus if the node to be deleted is the root... this routine really should return an integer with 0 for success, 1 for failure and errno = ESRCH or something. */ retval = p; /* We don't unchain the node we want to delete. Instead, we overwrite it with its successor and unchain the successor. If there is no successor, we really unchain the node to be deleted. */ root = *rootp; r = root>right; q = root>left; if (q == NULL  r == NULL) unchained = root; else { node *parent = rootp, *up = &root>right; for (;;) { if (sp == stacksize) abort (); nodestack[sp++] = parent; parent = up; if ((*up)>left == NULL) break; up = &(*up)>left; } unchained = *up; } /* We know that either the left or right successor of UNCHAINED is NULL. R becomes the other one, it is chained into the parent of UNCHAINED. */ r = unchained>left; if (r == NULL) r = unchained>right; if (sp == 0) *rootp = r; else { q = *nodestack[sp1]; if (unchained == q>right) q>right = r; else q>left = r; } if (unchained != root) root>key = unchained>key; if (!unchained>red) { /* Now we lost a black edge, which means that the number of black edges on every path is no longer constant. We must balance the tree. */ /* NODESTACK now contains all parents of R. R is likely to be NULL in the first iteration. */ /* NULL nodes are considered black throughout  this is necessary for correctness. */ while (sp > 0 && (r == NULL  !r>red)) { node *pp = nodestack[sp  1]; p = *pp; /* Two symmetric cases. */ if (r == p>left) { /* Q is R's brother, P is R's parent. The subtree with root R has one black edge less than the subtree with root Q. */ q = p>right; if (q>red) { /* If Q is red, we know that P is black. We rotate P left so that Q becomes the top node in the tree, with P below it. P is colored red, Q is colored black. This action does not change the black edge count for any leaf in the tree, but we will be able to recognize one of the following situations, which all require that Q is black. */ q>red = 0; p>red = 1; /* Left rotate p. */ p>right = q>left; q>left = p; *pp = q; /* Make sure pp is right if the case below tries to use it. */ nodestack[sp++] = pp = &q>left; q = p>right; } /* We know that Q can't be NULL here. We also know that Q is black. */ if ((q>left == NULL  !q>left>red) && (q>right == NULL  !q>right>red)) { /* Q has two black successors. We can simply color Q red. The whole subtree with root P is now missing one black edge. Note that this action can temporarily make the tree invalid (if P is red). But we will exit the loop in that case and set P black, which both makes the tree valid and also makes the black edge count come out right. If P is black, we are at least one step closer to the root and we'll try again the next iteration. */ q>red = 1; r = p; } else { /* Q is black, one of Q's successors is red. We can repair the tree with one operation and will exit the loop afterwards. */ if (q>right == NULL  !q>right>red) { /* The left one is red. We perform the same action as in maybe_split_for_insert where two red edges are adjacent but point in different directions: Q's left successor (let's call it Q2) becomes the top of the subtree we are looking at, its parent (Q) and grandparent (P) become its successors. The former successors of Q2 are placed below P and Q. P becomes black, and Q2 gets the color that P had. This changes the black edge count only for node R and its successors. */ node q2 = q>left; q2>red = p>red; p>right = q2>left; q>left = q2>right; q2>right = q; q2>left = p; *pp = q2; p>red = 0; } else { /* It's the right one. Rotate P left. P becomes black, and Q gets the color that P had. Q's right successor also becomes black. This changes the black edge count only for node R and its successors. */ q>red = p>red; p>red = 0; q>right>red = 0; /* left rotate p */ p>right = q>left; q>left = p; *pp = q; } /* We're done. */ sp = 1; r = NULL; } } else { /* Comments: see above. */ q = p>left; if (q>red) { q>red = 0; p>red = 1; p>left = q>right; q>right = p; *pp = q; nodestack[sp++] = pp = &q>right; q = p>left; } if ((q>right == NULL  !q>right>red) && (q>left == NULL  !q>left>red)) { q>red = 1; r = p; } else { if (q>left == NULL  !q>left>red) { node q2 = q>right; q2>red = p>red; p>left = q2>right; q>right = q2>left; q2>left = q; q2>right = p; *pp = q2; p>red = 0; } else { q>red = p>red; p>red = 0; q>left>red = 0; p>left = q>right; q>right = p; *pp = q; } sp = 1; r = NULL; } } sp; } if (r != NULL) r>red = 0; } free (unchained); return retval; }
void* __tfind  (  void *  key, 
void *const *  vrootp,  
__compar_fn_t  compar  
)  const 
void* __tsearch  (  const void *  key, 
void **  vrootp,  
__compar_fn_t  compar  
) 
Definition at line 264 of file tsearch.c.
{ node q; node *parentp = NULL, *gparentp = NULL; node *rootp = (node *) vrootp; node *nextp; int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */ if (rootp == NULL) return NULL; /* This saves some additional tests below. */ if (*rootp != NULL) (*rootp)>red = 0; CHECK_TREE (*rootp); nextp = rootp; while (*nextp != NULL) { node root = *rootp; r = (*compar) (key, root>key); if (r == 0) return root; maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0); /* If that did any rotations, parentp and gparentp are now garbage. That doesn't matter, because the values they contain are never used again in that case. */ nextp = r < 0 ? &root>left : &root>right; if (*nextp == NULL) break; gparentp = parentp; parentp = rootp; rootp = nextp; gp_r = p_r; p_r = r; } q = (struct node_t *) malloc (sizeof (struct node_t)); if (q != NULL) { *nextp = q; /* link new node to old */ q>key = key; /* initialize new node */ q>red = 1; q>left = q>right = NULL; if (nextp != rootp) /* There may be two red edges in a row now, which we must avoid by rotating the tree. */ maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1); } return q; }
void __twalk  (  const void *  vroot, 
__action_fn_t  action  
) 
Definition at line 641 of file tsearch.c.
{ const_node root = (const_node) vroot; CHECK_TREE (root); if (root != NULL && action != NULL) trecurse (root, action, 0); }
static void maybe_split_for_insert  (  node *  rootp, 
node *  parentp,  
node *  gparentp,  
int  p_r,  
int  gp_r,  
int  mode  
)  [static] 
Definition at line 181 of file tsearch.c.
{ node root = *rootp; node *rp, *lp; rp = &(*rootp)>right; lp = &(*rootp)>left; /* See if we have to split this node (both successors red). */ if (mode == 1  ((*rp) != NULL && (*lp) != NULL && (*rp)>red && (*lp)>red)) { /* This node becomes red, its successors black. */ root>red = 1; if (*rp) (*rp)>red = 0; if (*lp) (*lp)>red = 0; /* If the parent of this node is also red, we have to do rotations. */ if (parentp != NULL && (*parentp)>red) { node gp = *gparentp; node p = *parentp; /* There are two main cases: 1. The edge types (left or right) of the two red edges differ. 2. Both red edges are of the same type. There exist two symmetries of each case, so there is a total of 4 cases. */ if ((p_r > 0) != (gp_r > 0)) { /* Put the child at the top of the tree, with its parent and grandparent as successors. */ p>red = 1; gp>red = 1; root>red = 0; if (p_r < 0) { /* Child is left of parent. */ p>left = *rp; *rp = p; gp>right = *lp; *lp = gp; } else { /* Child is right of parent. */ p>right = *lp; *lp = p; gp>left = *rp; *rp = gp; } *gparentp = root; } else { *gparentp = *parentp; /* Parent becomes the top of the tree, grandparent and child are its successors. */ p>red = 0; gp>red = 1; if (p_r < 0) { /* Left edges. */ gp>left = p>right; p>right = gp; } else { /* Right edges. */ gp>right = p>left; p>left = gp; } } } } }
static void internal_function trecurse  (  const void *  vroot, 
__action_fn_t  action,  
int  level  
)  [static] 
Definition at line 618 of file tsearch.c.
{ const_node root = (const_node) vroot; if (root>left == NULL && root>right == NULL) (*action) (root, leaf, level); else { (*action) (root, preorder, level); if (root>left != NULL) trecurse (root>left, action, level + 1); (*action) (root, postorder, level); if (root>right != NULL) trecurse (root>right, action, level + 1); (*action) (root, endorder, level); } }