xref: /freebsd/crypto/heimdal/lib/roken/tsearch.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1*ae771770SStanislav Sedov /*
2*ae771770SStanislav Sedov  * Tree search generalized from Knuth (6.2.2) Algorithm T just like
3*ae771770SStanislav Sedov  * the AT&T man page says.
4*ae771770SStanislav Sedov  *
5*ae771770SStanislav Sedov  * The node_t structure is for internal use only, lint doesn't grok it.
6*ae771770SStanislav Sedov  *
7*ae771770SStanislav Sedov  * Written by reading the System V Interface Definition, not the code.
8*ae771770SStanislav Sedov  *
9*ae771770SStanislav Sedov  * Totally public domain.
10*ae771770SStanislav Sedov  *
11*ae771770SStanislav Sedov  * $NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $
12*ae771770SStanislav Sedov  * $NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $
13*ae771770SStanislav Sedov  * $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
14*ae771770SStanislav Sedov  * $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
15*ae771770SStanislav Sedov  */
16*ae771770SStanislav Sedov 
17*ae771770SStanislav Sedov #include <config.h>
18*ae771770SStanislav Sedov #include "roken.h"
19*ae771770SStanislav Sedov #include "search.h"
20*ae771770SStanislav Sedov #include <stdlib.h>
21*ae771770SStanislav Sedov 
22*ae771770SStanislav Sedov typedef struct node {
23*ae771770SStanislav Sedov   char         *key;
24*ae771770SStanislav Sedov   struct node  *llink, *rlink;
25*ae771770SStanislav Sedov } node_t;
26*ae771770SStanislav Sedov 
27*ae771770SStanislav Sedov #ifndef __DECONST
28*ae771770SStanislav Sedov #define __DECONST(type, var)    ((type)(uintptr_t)(const void *)(var))
29*ae771770SStanislav Sedov #endif
30*ae771770SStanislav Sedov 
31*ae771770SStanislav Sedov /*
32*ae771770SStanislav Sedov  * find or insert datum into search tree
33*ae771770SStanislav Sedov  *
34*ae771770SStanislav Sedov  * Parameters:
35*ae771770SStanislav Sedov  *	vkey:	key to be located
36*ae771770SStanislav Sedov  *	vrootp:	address of tree root
37*ae771770SStanislav Sedov  */
38*ae771770SStanislav Sedov 
39*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION void *
rk_tsearch(const void * vkey,void ** vrootp,int (* compar)(const void *,const void *))40*ae771770SStanislav Sedov rk_tsearch(const void *vkey, void **vrootp,
41*ae771770SStanislav Sedov 	int (*compar)(const void *, const void *))
42*ae771770SStanislav Sedov {
43*ae771770SStanislav Sedov 	node_t *q;
44*ae771770SStanislav Sedov 	node_t **rootp = (node_t **)vrootp;
45*ae771770SStanislav Sedov 
46*ae771770SStanislav Sedov 	if (rootp == NULL)
47*ae771770SStanislav Sedov 		return NULL;
48*ae771770SStanislav Sedov 
49*ae771770SStanislav Sedov 	while (*rootp != NULL) {	/* Knuth's T1: */
50*ae771770SStanislav Sedov 		int r;
51*ae771770SStanislav Sedov 
52*ae771770SStanislav Sedov 		if ((r = (*compar)(vkey, (*rootp)->key)) == 0)	/* T2: */
53*ae771770SStanislav Sedov 			return *rootp;		/* we found it! */
54*ae771770SStanislav Sedov 
55*ae771770SStanislav Sedov 		rootp = (r < 0) ?
56*ae771770SStanislav Sedov 		    &(*rootp)->llink :		/* T3: follow left branch */
57*ae771770SStanislav Sedov 		    &(*rootp)->rlink;		/* T4: follow right branch */
58*ae771770SStanislav Sedov 	}
59*ae771770SStanislav Sedov 
60*ae771770SStanislav Sedov 	q = malloc(sizeof(node_t));		/* T5: key not found */
61*ae771770SStanislav Sedov 	if (q != 0) {				/* make new node */
62*ae771770SStanislav Sedov 		*rootp = q;			/* link new node to old */
63*ae771770SStanislav Sedov 		/* LINTED const castaway ok */
64*ae771770SStanislav Sedov 		q->key = __DECONST(void *, vkey); /* initialize new node */
65*ae771770SStanislav Sedov 		q->llink = q->rlink = NULL;
66*ae771770SStanislav Sedov 	}
67*ae771770SStanislav Sedov 	return q;
68*ae771770SStanislav Sedov }
69*ae771770SStanislav Sedov 
70*ae771770SStanislav Sedov /*
71*ae771770SStanislav Sedov  * Walk the nodes of a tree
72*ae771770SStanislav Sedov  *
73*ae771770SStanislav Sedov  * Parameters:
74*ae771770SStanislav Sedov  *	root:	Root of the tree to be walked
75*ae771770SStanislav Sedov  */
76*ae771770SStanislav Sedov static void
trecurse(const node_t * root,void (* action)(const void *,VISIT,int),int level)77*ae771770SStanislav Sedov trecurse(const node_t *root, void (*action)(const void *, VISIT, int),
78*ae771770SStanislav Sedov 	 int level)
79*ae771770SStanislav Sedov {
80*ae771770SStanislav Sedov 
81*ae771770SStanislav Sedov 	if (root->llink == NULL && root->rlink == NULL)
82*ae771770SStanislav Sedov 		(*action)(root, leaf, level);
83*ae771770SStanislav Sedov 	else {
84*ae771770SStanislav Sedov 		(*action)(root, preorder, level);
85*ae771770SStanislav Sedov 		if (root->llink != NULL)
86*ae771770SStanislav Sedov 			trecurse(root->llink, action, level + 1);
87*ae771770SStanislav Sedov 		(*action)(root, postorder, level);
88*ae771770SStanislav Sedov 		if (root->rlink != NULL)
89*ae771770SStanislav Sedov 			trecurse(root->rlink, action, level + 1);
90*ae771770SStanislav Sedov 		(*action)(root, endorder, level);
91*ae771770SStanislav Sedov 	}
92*ae771770SStanislav Sedov }
93*ae771770SStanislav Sedov 
94*ae771770SStanislav Sedov /*
95*ae771770SStanislav Sedov  * Walk the nodes of a tree
96*ae771770SStanislav Sedov  *
97*ae771770SStanislav Sedov  * Parameters:
98*ae771770SStanislav Sedov  *	vroot:	Root of the tree to be walked
99*ae771770SStanislav Sedov  */
100*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION void
rk_twalk(const void * vroot,void (* action)(const void *,VISIT,int))101*ae771770SStanislav Sedov rk_twalk(const void *vroot,
102*ae771770SStanislav Sedov       void (*action)(const void *, VISIT, int))
103*ae771770SStanislav Sedov {
104*ae771770SStanislav Sedov 	if (vroot != NULL && action != NULL)
105*ae771770SStanislav Sedov 		trecurse(vroot, action, 0);
106*ae771770SStanislav Sedov }
107*ae771770SStanislav Sedov 
108*ae771770SStanislav Sedov /*
109*ae771770SStanislav Sedov  * delete node with given key
110*ae771770SStanislav Sedov  *
111*ae771770SStanislav Sedov  * vkey:   key to be deleted
112*ae771770SStanislav Sedov  * vrootp: address of the root of the tree
113*ae771770SStanislav Sedov  * compar: function to carry out node comparisons
114*ae771770SStanislav Sedov  */
115*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION void *
rk_tdelete(const void * vkey,void ** vrootp,int (* compar)(const void *,const void *))116*ae771770SStanislav Sedov rk_tdelete(const void * vkey, void ** vrootp,
117*ae771770SStanislav Sedov 	int (*compar)(const void *, const void *))
118*ae771770SStanislav Sedov {
119*ae771770SStanislav Sedov 	node_t **rootp = (node_t **)vrootp;
120*ae771770SStanislav Sedov 	node_t *p, *q, *r;
121*ae771770SStanislav Sedov 	int cmp;
122*ae771770SStanislav Sedov 
123*ae771770SStanislav Sedov 	if (rootp == NULL || (p = *rootp) == NULL)
124*ae771770SStanislav Sedov 		return NULL;
125*ae771770SStanislav Sedov 
126*ae771770SStanislav Sedov 	while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
127*ae771770SStanislav Sedov 		p = *rootp;
128*ae771770SStanislav Sedov 		rootp = (cmp < 0) ?
129*ae771770SStanislav Sedov 		    &(*rootp)->llink :		/* follow llink branch */
130*ae771770SStanislav Sedov 		    &(*rootp)->rlink;		/* follow rlink branch */
131*ae771770SStanislav Sedov 		if (*rootp == NULL)
132*ae771770SStanislav Sedov 			return NULL;		/* key not found */
133*ae771770SStanislav Sedov 	}
134*ae771770SStanislav Sedov 	r = (*rootp)->rlink;			/* D1: */
135*ae771770SStanislav Sedov 	if ((q = (*rootp)->llink) == NULL)	/* Left NULL? */
136*ae771770SStanislav Sedov 		q = r;
137*ae771770SStanislav Sedov 	else if (r != NULL) {			/* Right link is NULL? */
138*ae771770SStanislav Sedov 		if (r->llink == NULL) {		/* D2: Find successor */
139*ae771770SStanislav Sedov 			r->llink = q;
140*ae771770SStanislav Sedov 			q = r;
141*ae771770SStanislav Sedov 		} else {			/* D3: Find NULL link */
142*ae771770SStanislav Sedov 			for (q = r->llink; q->llink != NULL; q = r->llink)
143*ae771770SStanislav Sedov 				r = q;
144*ae771770SStanislav Sedov 			r->llink = q->rlink;
145*ae771770SStanislav Sedov 			q->llink = (*rootp)->llink;
146*ae771770SStanislav Sedov 			q->rlink = (*rootp)->rlink;
147*ae771770SStanislav Sedov 		}
148*ae771770SStanislav Sedov 	}
149*ae771770SStanislav Sedov 	free(*rootp);				/* D4: Free node */
150*ae771770SStanislav Sedov 	*rootp = q;				/* link parent to new node */
151*ae771770SStanislav Sedov 	return p;
152*ae771770SStanislav Sedov }
153*ae771770SStanislav Sedov 
154*ae771770SStanislav Sedov /*
155*ae771770SStanislav Sedov  * find a node, or return 0
156*ae771770SStanislav Sedov  *
157*ae771770SStanislav Sedov  * Parameters:
158*ae771770SStanislav Sedov  *	vkey:	key to be found
159*ae771770SStanislav Sedov  *	vrootp:	address of the tree root
160*ae771770SStanislav Sedov  */
161*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION void *
rk_tfind(const void * vkey,void * const * vrootp,int (* compar)(const void *,const void *))162*ae771770SStanislav Sedov rk_tfind(const void *vkey, void * const *vrootp,
163*ae771770SStanislav Sedov       int (*compar)(const void *, const void *))
164*ae771770SStanislav Sedov {
165*ae771770SStanislav Sedov 	node_t **rootp = (node_t **)vrootp;
166*ae771770SStanislav Sedov 
167*ae771770SStanislav Sedov 	if (rootp == NULL)
168*ae771770SStanislav Sedov 		return NULL;
169*ae771770SStanislav Sedov 
170*ae771770SStanislav Sedov 	while (*rootp != NULL) {		/* T1: */
171*ae771770SStanislav Sedov 		int r;
172*ae771770SStanislav Sedov 
173*ae771770SStanislav Sedov 		if ((r = (*compar)(vkey, (*rootp)->key)) == 0)	/* T2: */
174*ae771770SStanislav Sedov 			return *rootp;		/* key found */
175*ae771770SStanislav Sedov 		rootp = (r < 0) ?
176*ae771770SStanislav Sedov 		    &(*rootp)->llink :		/* T3: follow left branch */
177*ae771770SStanislav Sedov 		    &(*rootp)->rlink;		/* T4: follow right branch */
178*ae771770SStanislav Sedov 	}
179*ae771770SStanislav Sedov 	return NULL;
180*ae771770SStanislav Sedov }
181