xref: /illumos-gate/usr/src/tools/smatch/src/avl.c (revision 1f5207b7)
1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2010 Joseph Adams <joeyadams3.14159@gmail.com>
3*1f5207b7SJohn Levon  *
4*1f5207b7SJohn Levon  * Permission is hereby granted, free of charge, to any person obtaining a copy
5*1f5207b7SJohn Levon  * of this software and associated documentation files (the "Software"), to deal
6*1f5207b7SJohn Levon  * in the Software without restriction, including without limitation the rights
7*1f5207b7SJohn Levon  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8*1f5207b7SJohn Levon  * copies of the Software, and to permit persons to whom the Software is
9*1f5207b7SJohn Levon  * furnished to do so, subject to the following conditions:
10*1f5207b7SJohn Levon  *
11*1f5207b7SJohn Levon  * The above copyright notice and this permission notice shall be included in
12*1f5207b7SJohn Levon  * all copies or substantial portions of the Software.
13*1f5207b7SJohn Levon  *
14*1f5207b7SJohn Levon  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*1f5207b7SJohn Levon  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*1f5207b7SJohn Levon  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*1f5207b7SJohn Levon  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*1f5207b7SJohn Levon  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19*1f5207b7SJohn Levon  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20*1f5207b7SJohn Levon  * THE SOFTWARE.
21*1f5207b7SJohn Levon  */
22*1f5207b7SJohn Levon 
23*1f5207b7SJohn Levon #include <assert.h>
24*1f5207b7SJohn Levon #include <stdlib.h>
25*1f5207b7SJohn Levon 
26*1f5207b7SJohn Levon #include "smatch.h"
27*1f5207b7SJohn Levon #include "smatch_slist.h"
28*1f5207b7SJohn Levon 
29*1f5207b7SJohn Levon static AvlNode *mkNode(const struct sm_state *sm);
30*1f5207b7SJohn Levon static void freeNode(AvlNode *node);
31*1f5207b7SJohn Levon 
32*1f5207b7SJohn Levon static AvlNode *lookup(const struct stree *avl, AvlNode *node, const struct sm_state *sm);
33*1f5207b7SJohn Levon 
34*1f5207b7SJohn Levon static bool insert_sm(struct stree *avl, AvlNode **p, const struct sm_state *sm);
35*1f5207b7SJohn Levon static bool remove_sm(struct stree *avl, AvlNode **p, const struct sm_state *sm, AvlNode **ret);
36*1f5207b7SJohn Levon static bool removeExtremum(AvlNode **p, int side, AvlNode **ret);
37*1f5207b7SJohn Levon 
38*1f5207b7SJohn Levon static int sway(AvlNode **p, int sway);
39*1f5207b7SJohn Levon static void balance(AvlNode **p, int side);
40*1f5207b7SJohn Levon 
41*1f5207b7SJohn Levon static bool checkBalances(AvlNode *node, int *height);
42*1f5207b7SJohn Levon static bool checkOrder(struct stree *avl);
43*1f5207b7SJohn Levon static size_t countNode(AvlNode *node);
44*1f5207b7SJohn Levon 
45*1f5207b7SJohn Levon int unfree_stree;
46*1f5207b7SJohn Levon 
47*1f5207b7SJohn Levon /*
48*1f5207b7SJohn Levon  * Utility macros for converting between
49*1f5207b7SJohn Levon  * "balance" values (-1 or 1) and "side" values (0 or 1).
50*1f5207b7SJohn Levon  *
51*1f5207b7SJohn Levon  * bal(0)   == -1
52*1f5207b7SJohn Levon  * bal(1)   == +1
53*1f5207b7SJohn Levon  * side(-1) == 0
54*1f5207b7SJohn Levon  * side(+1) == 1
55*1f5207b7SJohn Levon  */
56*1f5207b7SJohn Levon #define bal(side) ((side) == 0 ? -1 : 1)
57*1f5207b7SJohn Levon #define side(bal) ((bal)  == 1 ?  1 : 0)
58*1f5207b7SJohn Levon 
avl_new(void)59*1f5207b7SJohn Levon static struct stree *avl_new(void)
60*1f5207b7SJohn Levon {
61*1f5207b7SJohn Levon 	struct stree *avl = malloc(sizeof(*avl));
62*1f5207b7SJohn Levon 
63*1f5207b7SJohn Levon 	unfree_stree++;
64*1f5207b7SJohn Levon 	assert(avl != NULL);
65*1f5207b7SJohn Levon 
66*1f5207b7SJohn Levon 	avl->root = NULL;
67*1f5207b7SJohn Levon 	avl->base_stree = NULL;
68*1f5207b7SJohn Levon 	avl->has_states = calloc(num_checks + 1, sizeof(char));
69*1f5207b7SJohn Levon 	avl->count = 0;
70*1f5207b7SJohn Levon 	avl->stree_id = 0;
71*1f5207b7SJohn Levon 	avl->references = 1;
72*1f5207b7SJohn Levon 	return avl;
73*1f5207b7SJohn Levon }
74*1f5207b7SJohn Levon 
free_stree(struct stree ** avl)75*1f5207b7SJohn Levon void free_stree(struct stree **avl)
76*1f5207b7SJohn Levon {
77*1f5207b7SJohn Levon 	if (!*avl)
78*1f5207b7SJohn Levon 		return;
79*1f5207b7SJohn Levon 
80*1f5207b7SJohn Levon 	assert((*avl)->references > 0);
81*1f5207b7SJohn Levon 
82*1f5207b7SJohn Levon 	(*avl)->references--;
83*1f5207b7SJohn Levon 	if ((*avl)->references != 0) {
84*1f5207b7SJohn Levon 		*avl = NULL;
85*1f5207b7SJohn Levon 		return;
86*1f5207b7SJohn Levon 	}
87*1f5207b7SJohn Levon 
88*1f5207b7SJohn Levon 	unfree_stree--;
89*1f5207b7SJohn Levon 
90*1f5207b7SJohn Levon 	freeNode((*avl)->root);
91*1f5207b7SJohn Levon 	free(*avl);
92*1f5207b7SJohn Levon 	*avl = NULL;
93*1f5207b7SJohn Levon }
94*1f5207b7SJohn Levon 
avl_lookup(const struct stree * avl,const struct sm_state * sm)95*1f5207b7SJohn Levon struct sm_state *avl_lookup(const struct stree *avl, const struct sm_state *sm)
96*1f5207b7SJohn Levon {
97*1f5207b7SJohn Levon 	AvlNode *found;
98*1f5207b7SJohn Levon 
99*1f5207b7SJohn Levon 	if (!avl)
100*1f5207b7SJohn Levon 		return NULL;
101*1f5207b7SJohn Levon 	if (sm->owner != USHRT_MAX &&
102*1f5207b7SJohn Levon 	    !avl->has_states[sm->owner])
103*1f5207b7SJohn Levon 		return NULL;
104*1f5207b7SJohn Levon 	found = lookup(avl, avl->root, sm);
105*1f5207b7SJohn Levon 	if (!found)
106*1f5207b7SJohn Levon 		return NULL;
107*1f5207b7SJohn Levon 	return (struct sm_state *)found->sm;
108*1f5207b7SJohn Levon }
109*1f5207b7SJohn Levon 
avl_lookup_node(const struct stree * avl,const struct sm_state * sm)110*1f5207b7SJohn Levon AvlNode *avl_lookup_node(const struct stree *avl, const struct sm_state *sm)
111*1f5207b7SJohn Levon {
112*1f5207b7SJohn Levon 	return lookup(avl, avl->root, sm);
113*1f5207b7SJohn Levon }
114*1f5207b7SJohn Levon 
stree_count(const struct stree * avl)115*1f5207b7SJohn Levon size_t stree_count(const struct stree *avl)
116*1f5207b7SJohn Levon {
117*1f5207b7SJohn Levon 	if (!avl)
118*1f5207b7SJohn Levon 		return 0;
119*1f5207b7SJohn Levon 	return avl->count;
120*1f5207b7SJohn Levon }
121*1f5207b7SJohn Levon 
clone_stree_real(struct stree * orig)122*1f5207b7SJohn Levon static struct stree *clone_stree_real(struct stree *orig)
123*1f5207b7SJohn Levon {
124*1f5207b7SJohn Levon 	struct stree *new = avl_new();
125*1f5207b7SJohn Levon 	AvlIter i;
126*1f5207b7SJohn Levon 
127*1f5207b7SJohn Levon 	avl_foreach(i, orig)
128*1f5207b7SJohn Levon 		avl_insert(&new, i.sm);
129*1f5207b7SJohn Levon 
130*1f5207b7SJohn Levon 	new->base_stree = orig->base_stree;
131*1f5207b7SJohn Levon 	return new;
132*1f5207b7SJohn Levon }
133*1f5207b7SJohn Levon 
avl_insert(struct stree ** avl,const struct sm_state * sm)134*1f5207b7SJohn Levon bool avl_insert(struct stree **avl, const struct sm_state *sm)
135*1f5207b7SJohn Levon {
136*1f5207b7SJohn Levon 	size_t old_count;
137*1f5207b7SJohn Levon 
138*1f5207b7SJohn Levon 	if (!*avl)
139*1f5207b7SJohn Levon 		*avl = avl_new();
140*1f5207b7SJohn Levon 	if ((*avl)->references > 1) {
141*1f5207b7SJohn Levon 		(*avl)->references--;
142*1f5207b7SJohn Levon 		*avl = clone_stree_real(*avl);
143*1f5207b7SJohn Levon 	}
144*1f5207b7SJohn Levon 	old_count = (*avl)->count;
145*1f5207b7SJohn Levon 	/* fortunately we never call get_state() on "unnull_path" */
146*1f5207b7SJohn Levon 	if (sm->owner != USHRT_MAX)
147*1f5207b7SJohn Levon 		(*avl)->has_states[sm->owner] = 1;
148*1f5207b7SJohn Levon 	insert_sm(*avl, &(*avl)->root, sm);
149*1f5207b7SJohn Levon 	return (*avl)->count != old_count;
150*1f5207b7SJohn Levon }
151*1f5207b7SJohn Levon 
avl_remove(struct stree ** avl,const struct sm_state * sm)152*1f5207b7SJohn Levon bool avl_remove(struct stree **avl, const struct sm_state *sm)
153*1f5207b7SJohn Levon {
154*1f5207b7SJohn Levon 	AvlNode *node = NULL;
155*1f5207b7SJohn Levon 
156*1f5207b7SJohn Levon 	if (!*avl)
157*1f5207b7SJohn Levon 		return false;
158*1f5207b7SJohn Levon 	/* it's fairly rare for smatch to call avl_remove */
159*1f5207b7SJohn Levon 	if ((*avl)->references > 1) {
160*1f5207b7SJohn Levon 		(*avl)->references--;
161*1f5207b7SJohn Levon 		*avl = clone_stree_real(*avl);
162*1f5207b7SJohn Levon 	}
163*1f5207b7SJohn Levon 
164*1f5207b7SJohn Levon 	remove_sm(*avl, &(*avl)->root, sm, &node);
165*1f5207b7SJohn Levon 
166*1f5207b7SJohn Levon 	if ((*avl)->count == 0)
167*1f5207b7SJohn Levon 		free_stree(avl);
168*1f5207b7SJohn Levon 
169*1f5207b7SJohn Levon 	if (node == NULL) {
170*1f5207b7SJohn Levon 		return false;
171*1f5207b7SJohn Levon 	} else {
172*1f5207b7SJohn Levon 		free(node);
173*1f5207b7SJohn Levon 		return true;
174*1f5207b7SJohn Levon 	}
175*1f5207b7SJohn Levon }
176*1f5207b7SJohn Levon 
mkNode(const struct sm_state * sm)177*1f5207b7SJohn Levon static AvlNode *mkNode(const struct sm_state *sm)
178*1f5207b7SJohn Levon {
179*1f5207b7SJohn Levon 	AvlNode *node = malloc(sizeof(*node));
180*1f5207b7SJohn Levon 
181*1f5207b7SJohn Levon 	assert(node != NULL);
182*1f5207b7SJohn Levon 
183*1f5207b7SJohn Levon 	node->sm = sm;
184*1f5207b7SJohn Levon 	node->lr[0] = NULL;
185*1f5207b7SJohn Levon 	node->lr[1] = NULL;
186*1f5207b7SJohn Levon 	node->balance = 0;
187*1f5207b7SJohn Levon 	return node;
188*1f5207b7SJohn Levon }
189*1f5207b7SJohn Levon 
freeNode(AvlNode * node)190*1f5207b7SJohn Levon static void freeNode(AvlNode *node)
191*1f5207b7SJohn Levon {
192*1f5207b7SJohn Levon 	if (node) {
193*1f5207b7SJohn Levon 		freeNode(node->lr[0]);
194*1f5207b7SJohn Levon 		freeNode(node->lr[1]);
195*1f5207b7SJohn Levon 		free(node);
196*1f5207b7SJohn Levon 	}
197*1f5207b7SJohn Levon }
198*1f5207b7SJohn Levon 
lookup(const struct stree * avl,AvlNode * node,const struct sm_state * sm)199*1f5207b7SJohn Levon static AvlNode *lookup(const struct stree *avl, AvlNode *node, const struct sm_state *sm)
200*1f5207b7SJohn Levon {
201*1f5207b7SJohn Levon 	int cmp;
202*1f5207b7SJohn Levon 
203*1f5207b7SJohn Levon 	if (node == NULL)
204*1f5207b7SJohn Levon 		return NULL;
205*1f5207b7SJohn Levon 
206*1f5207b7SJohn Levon 	cmp = cmp_tracker(sm, node->sm);
207*1f5207b7SJohn Levon 
208*1f5207b7SJohn Levon 	if (cmp < 0)
209*1f5207b7SJohn Levon 		return lookup(avl, node->lr[0], sm);
210*1f5207b7SJohn Levon 	if (cmp > 0)
211*1f5207b7SJohn Levon 		return lookup(avl, node->lr[1], sm);
212*1f5207b7SJohn Levon 	return node;
213*1f5207b7SJohn Levon }
214*1f5207b7SJohn Levon 
215*1f5207b7SJohn Levon /*
216*1f5207b7SJohn Levon  * Insert an sm into a subtree, rebalancing if necessary.
217*1f5207b7SJohn Levon  *
218*1f5207b7SJohn Levon  * Return true if the subtree's height increased.
219*1f5207b7SJohn Levon  */
insert_sm(struct stree * avl,AvlNode ** p,const struct sm_state * sm)220*1f5207b7SJohn Levon static bool insert_sm(struct stree *avl, AvlNode **p, const struct sm_state *sm)
221*1f5207b7SJohn Levon {
222*1f5207b7SJohn Levon 	if (*p == NULL) {
223*1f5207b7SJohn Levon 		*p = mkNode(sm);
224*1f5207b7SJohn Levon 		avl->count++;
225*1f5207b7SJohn Levon 		return true;
226*1f5207b7SJohn Levon 	} else {
227*1f5207b7SJohn Levon 		AvlNode *node = *p;
228*1f5207b7SJohn Levon 		int      cmp  = cmp_tracker(sm, node->sm);
229*1f5207b7SJohn Levon 
230*1f5207b7SJohn Levon 		if (cmp == 0) {
231*1f5207b7SJohn Levon 			node->sm = sm;
232*1f5207b7SJohn Levon 			return false;
233*1f5207b7SJohn Levon 		}
234*1f5207b7SJohn Levon 
235*1f5207b7SJohn Levon 		if (!insert_sm(avl, &node->lr[side(cmp)], sm))
236*1f5207b7SJohn Levon 			return false;
237*1f5207b7SJohn Levon 
238*1f5207b7SJohn Levon 		/* If tree's balance became -1 or 1, it means the tree's height grew due to insertion. */
239*1f5207b7SJohn Levon 		return sway(p, cmp) != 0;
240*1f5207b7SJohn Levon 	}
241*1f5207b7SJohn Levon }
242*1f5207b7SJohn Levon 
243*1f5207b7SJohn Levon /*
244*1f5207b7SJohn Levon  * Remove the node matching the given sm.
245*1f5207b7SJohn Levon  * If present, return the removed node through *ret .
246*1f5207b7SJohn Levon  * The returned node's lr and balance are meaningless.
247*1f5207b7SJohn Levon  *
248*1f5207b7SJohn Levon  * Return true if the subtree's height decreased.
249*1f5207b7SJohn Levon  */
remove_sm(struct stree * avl,AvlNode ** p,const struct sm_state * sm,AvlNode ** ret)250*1f5207b7SJohn Levon static bool remove_sm(struct stree *avl, AvlNode **p, const struct sm_state *sm, AvlNode **ret)
251*1f5207b7SJohn Levon {
252*1f5207b7SJohn Levon 	if (p == NULL || *p == NULL) {
253*1f5207b7SJohn Levon 		return false;
254*1f5207b7SJohn Levon 	} else {
255*1f5207b7SJohn Levon 		AvlNode *node = *p;
256*1f5207b7SJohn Levon 		int      cmp  = cmp_tracker(sm, node->sm);
257*1f5207b7SJohn Levon 
258*1f5207b7SJohn Levon 		if (cmp == 0) {
259*1f5207b7SJohn Levon 			*ret = node;
260*1f5207b7SJohn Levon 			avl->count--;
261*1f5207b7SJohn Levon 
262*1f5207b7SJohn Levon 			if (node->lr[0] != NULL && node->lr[1] != NULL) {
263*1f5207b7SJohn Levon 				AvlNode *replacement;
264*1f5207b7SJohn Levon 				int      side;
265*1f5207b7SJohn Levon 				bool     shrunk;
266*1f5207b7SJohn Levon 
267*1f5207b7SJohn Levon 				/* Pick a subtree to pull the replacement from such that
268*1f5207b7SJohn Levon 				 * this node doesn't have to be rebalanced. */
269*1f5207b7SJohn Levon 				side = node->balance <= 0 ? 0 : 1;
270*1f5207b7SJohn Levon 
271*1f5207b7SJohn Levon 				shrunk = removeExtremum(&node->lr[side], 1 - side, &replacement);
272*1f5207b7SJohn Levon 
273*1f5207b7SJohn Levon 				replacement->lr[0]   = node->lr[0];
274*1f5207b7SJohn Levon 				replacement->lr[1]   = node->lr[1];
275*1f5207b7SJohn Levon 				replacement->balance = node->balance;
276*1f5207b7SJohn Levon 				*p = replacement;
277*1f5207b7SJohn Levon 
278*1f5207b7SJohn Levon 				if (!shrunk)
279*1f5207b7SJohn Levon 					return false;
280*1f5207b7SJohn Levon 
281*1f5207b7SJohn Levon 				replacement->balance -= bal(side);
282*1f5207b7SJohn Levon 
283*1f5207b7SJohn Levon 				/* If tree's balance became 0, it means the tree's height shrank due to removal. */
284*1f5207b7SJohn Levon 				return replacement->balance == 0;
285*1f5207b7SJohn Levon 			}
286*1f5207b7SJohn Levon 
287*1f5207b7SJohn Levon 			if (node->lr[0] != NULL)
288*1f5207b7SJohn Levon 				*p = node->lr[0];
289*1f5207b7SJohn Levon 			else
290*1f5207b7SJohn Levon 				*p = node->lr[1];
291*1f5207b7SJohn Levon 
292*1f5207b7SJohn Levon 			return true;
293*1f5207b7SJohn Levon 
294*1f5207b7SJohn Levon 		} else {
295*1f5207b7SJohn Levon 			if (!remove_sm(avl, &node->lr[side(cmp)], sm, ret))
296*1f5207b7SJohn Levon 				return false;
297*1f5207b7SJohn Levon 
298*1f5207b7SJohn Levon 			/* If tree's balance became 0, it means the tree's height shrank due to removal. */
299*1f5207b7SJohn Levon 			return sway(p, -cmp) == 0;
300*1f5207b7SJohn Levon 		}
301*1f5207b7SJohn Levon 	}
302*1f5207b7SJohn Levon }
303*1f5207b7SJohn Levon 
304*1f5207b7SJohn Levon /*
305*1f5207b7SJohn Levon  * Remove either the left-most (if side == 0) or right-most (if side == 1)
306*1f5207b7SJohn Levon  * node in a subtree, returning the removed node through *ret .
307*1f5207b7SJohn Levon  * The returned node's lr and balance are meaningless.
308*1f5207b7SJohn Levon  *
309*1f5207b7SJohn Levon  * The subtree must not be empty (i.e. *p must not be NULL).
310*1f5207b7SJohn Levon  *
311*1f5207b7SJohn Levon  * Return true if the subtree's height decreased.
312*1f5207b7SJohn Levon  */
removeExtremum(AvlNode ** p,int side,AvlNode ** ret)313*1f5207b7SJohn Levon static bool removeExtremum(AvlNode **p, int side, AvlNode **ret)
314*1f5207b7SJohn Levon {
315*1f5207b7SJohn Levon 	AvlNode *node = *p;
316*1f5207b7SJohn Levon 
317*1f5207b7SJohn Levon 	if (node->lr[side] == NULL) {
318*1f5207b7SJohn Levon 		*ret = node;
319*1f5207b7SJohn Levon 		*p = node->lr[1 - side];
320*1f5207b7SJohn Levon 		return true;
321*1f5207b7SJohn Levon 	}
322*1f5207b7SJohn Levon 
323*1f5207b7SJohn Levon 	if (!removeExtremum(&node->lr[side], side, ret))
324*1f5207b7SJohn Levon 		return false;
325*1f5207b7SJohn Levon 
326*1f5207b7SJohn Levon 	/* If tree's balance became 0, it means the tree's height shrank due to removal. */
327*1f5207b7SJohn Levon 	return sway(p, -bal(side)) == 0;
328*1f5207b7SJohn Levon }
329*1f5207b7SJohn Levon 
330*1f5207b7SJohn Levon /*
331*1f5207b7SJohn Levon  * Rebalance a node if necessary.  Think of this function
332*1f5207b7SJohn Levon  * as a higher-level interface to balance().
333*1f5207b7SJohn Levon  *
334*1f5207b7SJohn Levon  * sway must be either -1 or 1, and indicates what was added to
335*1f5207b7SJohn Levon  * the balance of this node by a prior operation.
336*1f5207b7SJohn Levon  *
337*1f5207b7SJohn Levon  * Return the new balance of the subtree.
338*1f5207b7SJohn Levon  */
sway(AvlNode ** p,int sway)339*1f5207b7SJohn Levon static int sway(AvlNode **p, int sway)
340*1f5207b7SJohn Levon {
341*1f5207b7SJohn Levon 	if ((*p)->balance != sway)
342*1f5207b7SJohn Levon 		(*p)->balance += sway;
343*1f5207b7SJohn Levon 	else
344*1f5207b7SJohn Levon 		balance(p, side(sway));
345*1f5207b7SJohn Levon 
346*1f5207b7SJohn Levon 	return (*p)->balance;
347*1f5207b7SJohn Levon }
348*1f5207b7SJohn Levon 
349*1f5207b7SJohn Levon /*
350*1f5207b7SJohn Levon  * Perform tree rotations on an unbalanced node.
351*1f5207b7SJohn Levon  *
352*1f5207b7SJohn Levon  * side == 0 means the node's balance is -2 .
353*1f5207b7SJohn Levon  * side == 1 means the node's balance is +2 .
354*1f5207b7SJohn Levon  */
balance(AvlNode ** p,int side)355*1f5207b7SJohn Levon static void balance(AvlNode **p, int side)
356*1f5207b7SJohn Levon {
357*1f5207b7SJohn Levon 	AvlNode  *node  = *p,
358*1f5207b7SJohn Levon 	         *child = node->lr[side];
359*1f5207b7SJohn Levon 	int opposite    = 1 - side;
360*1f5207b7SJohn Levon 	int bal         = bal(side);
361*1f5207b7SJohn Levon 
362*1f5207b7SJohn Levon 	if (child->balance != -bal) {
363*1f5207b7SJohn Levon 		/* Left-left (side == 0) or right-right (side == 1) */
364*1f5207b7SJohn Levon 		node->lr[side]      = child->lr[opposite];
365*1f5207b7SJohn Levon 		child->lr[opposite] = node;
366*1f5207b7SJohn Levon 		*p = child;
367*1f5207b7SJohn Levon 
368*1f5207b7SJohn Levon 		child->balance -= bal;
369*1f5207b7SJohn Levon 		node->balance = -child->balance;
370*1f5207b7SJohn Levon 
371*1f5207b7SJohn Levon 	} else {
372*1f5207b7SJohn Levon 		/* Left-right (side == 0) or right-left (side == 1) */
373*1f5207b7SJohn Levon 		AvlNode *grandchild = child->lr[opposite];
374*1f5207b7SJohn Levon 
375*1f5207b7SJohn Levon 		node->lr[side]           = grandchild->lr[opposite];
376*1f5207b7SJohn Levon 		child->lr[opposite]      = grandchild->lr[side];
377*1f5207b7SJohn Levon 		grandchild->lr[side]     = child;
378*1f5207b7SJohn Levon 		grandchild->lr[opposite] = node;
379*1f5207b7SJohn Levon 		*p = grandchild;
380*1f5207b7SJohn Levon 
381*1f5207b7SJohn Levon 		node->balance       = 0;
382*1f5207b7SJohn Levon 		child->balance      = 0;
383*1f5207b7SJohn Levon 
384*1f5207b7SJohn Levon 		if (grandchild->balance == bal)
385*1f5207b7SJohn Levon 			node->balance  = -bal;
386*1f5207b7SJohn Levon 		else if (grandchild->balance == -bal)
387*1f5207b7SJohn Levon 			child->balance = bal;
388*1f5207b7SJohn Levon 
389*1f5207b7SJohn Levon 		grandchild->balance = 0;
390*1f5207b7SJohn Levon 	}
391*1f5207b7SJohn Levon }
392*1f5207b7SJohn Levon 
393*1f5207b7SJohn Levon 
394*1f5207b7SJohn Levon /************************* avl_check_invariants() *************************/
395*1f5207b7SJohn Levon 
avl_check_invariants(struct stree * avl)396*1f5207b7SJohn Levon bool avl_check_invariants(struct stree *avl)
397*1f5207b7SJohn Levon {
398*1f5207b7SJohn Levon 	int    dummy;
399*1f5207b7SJohn Levon 
400*1f5207b7SJohn Levon 	return checkBalances(avl->root, &dummy)
401*1f5207b7SJohn Levon 	    && checkOrder(avl)
402*1f5207b7SJohn Levon 	    && countNode(avl->root) == avl->count;
403*1f5207b7SJohn Levon }
404*1f5207b7SJohn Levon 
checkBalances(AvlNode * node,int * height)405*1f5207b7SJohn Levon static bool checkBalances(AvlNode *node, int *height)
406*1f5207b7SJohn Levon {
407*1f5207b7SJohn Levon 	if (node) {
408*1f5207b7SJohn Levon 		int h0, h1;
409*1f5207b7SJohn Levon 
410*1f5207b7SJohn Levon 		if (!checkBalances(node->lr[0], &h0))
411*1f5207b7SJohn Levon 			return false;
412*1f5207b7SJohn Levon 		if (!checkBalances(node->lr[1], &h1))
413*1f5207b7SJohn Levon 			return false;
414*1f5207b7SJohn Levon 
415*1f5207b7SJohn Levon 		if (node->balance != h1 - h0 || node->balance < -1 || node->balance > 1)
416*1f5207b7SJohn Levon 			return false;
417*1f5207b7SJohn Levon 
418*1f5207b7SJohn Levon 		*height = (h0 > h1 ? h0 : h1) + 1;
419*1f5207b7SJohn Levon 		return true;
420*1f5207b7SJohn Levon 	} else {
421*1f5207b7SJohn Levon 		*height = 0;
422*1f5207b7SJohn Levon 		return true;
423*1f5207b7SJohn Levon 	}
424*1f5207b7SJohn Levon }
425*1f5207b7SJohn Levon 
checkOrder(struct stree * avl)426*1f5207b7SJohn Levon static bool checkOrder(struct stree *avl)
427*1f5207b7SJohn Levon {
428*1f5207b7SJohn Levon 	AvlIter     i;
429*1f5207b7SJohn Levon 	const struct sm_state *last = NULL;
430*1f5207b7SJohn Levon 	bool        last_set = false;
431*1f5207b7SJohn Levon 
432*1f5207b7SJohn Levon 	avl_foreach(i, avl) {
433*1f5207b7SJohn Levon 		if (last_set && cmp_tracker(last, i.sm) >= 0)
434*1f5207b7SJohn Levon 			return false;
435*1f5207b7SJohn Levon 		last     = i.sm;
436*1f5207b7SJohn Levon 		last_set = true;
437*1f5207b7SJohn Levon 	}
438*1f5207b7SJohn Levon 
439*1f5207b7SJohn Levon 	return true;
440*1f5207b7SJohn Levon }
441*1f5207b7SJohn Levon 
countNode(AvlNode * node)442*1f5207b7SJohn Levon static size_t countNode(AvlNode *node)
443*1f5207b7SJohn Levon {
444*1f5207b7SJohn Levon 	if (node)
445*1f5207b7SJohn Levon 		return 1 + countNode(node->lr[0]) + countNode(node->lr[1]);
446*1f5207b7SJohn Levon 	else
447*1f5207b7SJohn Levon 		return 0;
448*1f5207b7SJohn Levon }
449*1f5207b7SJohn Levon 
450*1f5207b7SJohn Levon 
451*1f5207b7SJohn Levon /************************* Traversal *************************/
452*1f5207b7SJohn Levon 
avl_iter_begin(AvlIter * iter,struct stree * avl,AvlDirection dir)453*1f5207b7SJohn Levon void avl_iter_begin(AvlIter *iter, struct stree *avl, AvlDirection dir)
454*1f5207b7SJohn Levon {
455*1f5207b7SJohn Levon 	AvlNode *node;
456*1f5207b7SJohn Levon 
457*1f5207b7SJohn Levon 	iter->stack_index = 0;
458*1f5207b7SJohn Levon 	iter->direction   = dir;
459*1f5207b7SJohn Levon 
460*1f5207b7SJohn Levon 	if (!avl || !avl->root) {
461*1f5207b7SJohn Levon 		iter->sm      = NULL;
462*1f5207b7SJohn Levon 		iter->node     = NULL;
463*1f5207b7SJohn Levon 		return;
464*1f5207b7SJohn Levon 	}
465*1f5207b7SJohn Levon 	node = avl->root;
466*1f5207b7SJohn Levon 
467*1f5207b7SJohn Levon 	while (node->lr[dir] != NULL) {
468*1f5207b7SJohn Levon 		iter->stack[iter->stack_index++] = node;
469*1f5207b7SJohn Levon 		node = node->lr[dir];
470*1f5207b7SJohn Levon 	}
471*1f5207b7SJohn Levon 
472*1f5207b7SJohn Levon 	iter->sm   = (struct sm_state *) node->sm;
473*1f5207b7SJohn Levon 	iter->node  = node;
474*1f5207b7SJohn Levon }
475*1f5207b7SJohn Levon 
avl_iter_next(AvlIter * iter)476*1f5207b7SJohn Levon void avl_iter_next(AvlIter *iter)
477*1f5207b7SJohn Levon {
478*1f5207b7SJohn Levon 	AvlNode     *node = iter->node;
479*1f5207b7SJohn Levon 	AvlDirection dir  = iter->direction;
480*1f5207b7SJohn Levon 
481*1f5207b7SJohn Levon 	if (node == NULL)
482*1f5207b7SJohn Levon 		return;
483*1f5207b7SJohn Levon 
484*1f5207b7SJohn Levon 	node = node->lr[1 - dir];
485*1f5207b7SJohn Levon 	if (node != NULL) {
486*1f5207b7SJohn Levon 		while (node->lr[dir] != NULL) {
487*1f5207b7SJohn Levon 			iter->stack[iter->stack_index++] = node;
488*1f5207b7SJohn Levon 			node = node->lr[dir];
489*1f5207b7SJohn Levon 		}
490*1f5207b7SJohn Levon 	} else if (iter->stack_index > 0) {
491*1f5207b7SJohn Levon 		node = iter->stack[--iter->stack_index];
492*1f5207b7SJohn Levon 	} else {
493*1f5207b7SJohn Levon 		iter->sm      = NULL;
494*1f5207b7SJohn Levon 		iter->node     = NULL;
495*1f5207b7SJohn Levon 		return;
496*1f5207b7SJohn Levon 	}
497*1f5207b7SJohn Levon 
498*1f5207b7SJohn Levon 	iter->node  = node;
499*1f5207b7SJohn Levon 	iter->sm   = (struct sm_state *) node->sm;
500*1f5207b7SJohn Levon }
501*1f5207b7SJohn Levon 
clone_stree(struct stree * orig)502*1f5207b7SJohn Levon struct stree *clone_stree(struct stree *orig)
503*1f5207b7SJohn Levon {
504*1f5207b7SJohn Levon 	if (!orig)
505*1f5207b7SJohn Levon 		return NULL;
506*1f5207b7SJohn Levon 
507*1f5207b7SJohn Levon 	orig->references++;
508*1f5207b7SJohn Levon 	return orig;
509*1f5207b7SJohn Levon }
510*1f5207b7SJohn Levon 
set_stree_id(struct stree ** stree,int stree_id)511*1f5207b7SJohn Levon void set_stree_id(struct stree **stree, int stree_id)
512*1f5207b7SJohn Levon {
513*1f5207b7SJohn Levon 	if ((*stree)->stree_id != 0)
514*1f5207b7SJohn Levon 		*stree = clone_stree_real(*stree);
515*1f5207b7SJohn Levon 
516*1f5207b7SJohn Levon 	(*stree)->stree_id = stree_id;
517*1f5207b7SJohn Levon }
518*1f5207b7SJohn Levon 
get_stree_id(struct stree * stree)519*1f5207b7SJohn Levon int get_stree_id(struct stree *stree)
520*1f5207b7SJohn Levon {
521*1f5207b7SJohn Levon 	if (!stree)
522*1f5207b7SJohn Levon 		return -1;
523*1f5207b7SJohn Levon 	return stree->stree_id;
524*1f5207b7SJohn Levon }
525