xref: /aosp_15_r20/external/jemalloc_new/test/unit/rb.c (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker #include "test/jemalloc_test.h"
2*1208bc7eSAndroid Build Coastguard Worker 
3*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/rb.h"
4*1208bc7eSAndroid Build Coastguard Worker 
5*1208bc7eSAndroid Build Coastguard Worker #define rbtn_black_height(a_type, a_field, a_rbt, r_height) do {	\
6*1208bc7eSAndroid Build Coastguard Worker 	a_type *rbp_bh_t;						\
7*1208bc7eSAndroid Build Coastguard Worker 	for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; rbp_bh_t !=	\
8*1208bc7eSAndroid Build Coastguard Worker 	    NULL; rbp_bh_t = rbtn_left_get(a_type, a_field,		\
9*1208bc7eSAndroid Build Coastguard Worker 	    rbp_bh_t)) {						\
10*1208bc7eSAndroid Build Coastguard Worker 		if (!rbtn_red_get(a_type, a_field, rbp_bh_t)) {		\
11*1208bc7eSAndroid Build Coastguard Worker 		(r_height)++;						\
12*1208bc7eSAndroid Build Coastguard Worker 		}							\
13*1208bc7eSAndroid Build Coastguard Worker 	}								\
14*1208bc7eSAndroid Build Coastguard Worker } while (0)
15*1208bc7eSAndroid Build Coastguard Worker 
16*1208bc7eSAndroid Build Coastguard Worker typedef struct node_s node_t;
17*1208bc7eSAndroid Build Coastguard Worker 
18*1208bc7eSAndroid Build Coastguard Worker struct node_s {
19*1208bc7eSAndroid Build Coastguard Worker #define NODE_MAGIC 0x9823af7e
20*1208bc7eSAndroid Build Coastguard Worker 	uint32_t magic;
21*1208bc7eSAndroid Build Coastguard Worker 	rb_node(node_t) link;
22*1208bc7eSAndroid Build Coastguard Worker 	uint64_t key;
23*1208bc7eSAndroid Build Coastguard Worker };
24*1208bc7eSAndroid Build Coastguard Worker 
25*1208bc7eSAndroid Build Coastguard Worker static int
node_cmp(const node_t * a,const node_t * b)26*1208bc7eSAndroid Build Coastguard Worker node_cmp(const node_t *a, const node_t *b) {
27*1208bc7eSAndroid Build Coastguard Worker 	int ret;
28*1208bc7eSAndroid Build Coastguard Worker 
29*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_eq(a->magic, NODE_MAGIC, "Bad magic");
30*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_eq(b->magic, NODE_MAGIC, "Bad magic");
31*1208bc7eSAndroid Build Coastguard Worker 
32*1208bc7eSAndroid Build Coastguard Worker 	ret = (a->key > b->key) - (a->key < b->key);
33*1208bc7eSAndroid Build Coastguard Worker 	if (ret == 0) {
34*1208bc7eSAndroid Build Coastguard Worker 		/*
35*1208bc7eSAndroid Build Coastguard Worker 		 * Duplicates are not allowed in the tree, so force an
36*1208bc7eSAndroid Build Coastguard Worker 		 * arbitrary ordering for non-identical items with equal keys.
37*1208bc7eSAndroid Build Coastguard Worker 		 */
38*1208bc7eSAndroid Build Coastguard Worker 		ret = (((uintptr_t)a) > ((uintptr_t)b))
39*1208bc7eSAndroid Build Coastguard Worker 		    - (((uintptr_t)a) < ((uintptr_t)b));
40*1208bc7eSAndroid Build Coastguard Worker 	}
41*1208bc7eSAndroid Build Coastguard Worker 	return ret;
42*1208bc7eSAndroid Build Coastguard Worker }
43*1208bc7eSAndroid Build Coastguard Worker 
44*1208bc7eSAndroid Build Coastguard Worker typedef rb_tree(node_t) tree_t;
45*1208bc7eSAndroid Build Coastguard Worker rb_gen(static, tree_, tree_t, node_t, link, node_cmp);
46*1208bc7eSAndroid Build Coastguard Worker 
TEST_BEGIN(test_rb_empty)47*1208bc7eSAndroid Build Coastguard Worker TEST_BEGIN(test_rb_empty) {
48*1208bc7eSAndroid Build Coastguard Worker 	tree_t tree;
49*1208bc7eSAndroid Build Coastguard Worker 	node_t key;
50*1208bc7eSAndroid Build Coastguard Worker 
51*1208bc7eSAndroid Build Coastguard Worker 	tree_new(&tree);
52*1208bc7eSAndroid Build Coastguard Worker 
53*1208bc7eSAndroid Build Coastguard Worker 	assert_true(tree_empty(&tree), "Tree should be empty");
54*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_null(tree_first(&tree), "Unexpected node");
55*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_null(tree_last(&tree), "Unexpected node");
56*1208bc7eSAndroid Build Coastguard Worker 
57*1208bc7eSAndroid Build Coastguard Worker 	key.key = 0;
58*1208bc7eSAndroid Build Coastguard Worker 	key.magic = NODE_MAGIC;
59*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_null(tree_search(&tree, &key), "Unexpected node");
60*1208bc7eSAndroid Build Coastguard Worker 
61*1208bc7eSAndroid Build Coastguard Worker 	key.key = 0;
62*1208bc7eSAndroid Build Coastguard Worker 	key.magic = NODE_MAGIC;
63*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_null(tree_nsearch(&tree, &key), "Unexpected node");
64*1208bc7eSAndroid Build Coastguard Worker 
65*1208bc7eSAndroid Build Coastguard Worker 	key.key = 0;
66*1208bc7eSAndroid Build Coastguard Worker 	key.magic = NODE_MAGIC;
67*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_null(tree_psearch(&tree, &key), "Unexpected node");
68*1208bc7eSAndroid Build Coastguard Worker }
69*1208bc7eSAndroid Build Coastguard Worker TEST_END
70*1208bc7eSAndroid Build Coastguard Worker 
71*1208bc7eSAndroid Build Coastguard Worker static unsigned
tree_recurse(node_t * node,unsigned black_height,unsigned black_depth)72*1208bc7eSAndroid Build Coastguard Worker tree_recurse(node_t *node, unsigned black_height, unsigned black_depth) {
73*1208bc7eSAndroid Build Coastguard Worker 	unsigned ret = 0;
74*1208bc7eSAndroid Build Coastguard Worker 	node_t *left_node;
75*1208bc7eSAndroid Build Coastguard Worker 	node_t *right_node;
76*1208bc7eSAndroid Build Coastguard Worker 
77*1208bc7eSAndroid Build Coastguard Worker 	if (node == NULL) {
78*1208bc7eSAndroid Build Coastguard Worker 		return ret;
79*1208bc7eSAndroid Build Coastguard Worker 	}
80*1208bc7eSAndroid Build Coastguard Worker 
81*1208bc7eSAndroid Build Coastguard Worker 	left_node = rbtn_left_get(node_t, link, node);
82*1208bc7eSAndroid Build Coastguard Worker 	right_node = rbtn_right_get(node_t, link, node);
83*1208bc7eSAndroid Build Coastguard Worker 
84*1208bc7eSAndroid Build Coastguard Worker 	if (!rbtn_red_get(node_t, link, node)) {
85*1208bc7eSAndroid Build Coastguard Worker 		black_depth++;
86*1208bc7eSAndroid Build Coastguard Worker 	}
87*1208bc7eSAndroid Build Coastguard Worker 
88*1208bc7eSAndroid Build Coastguard Worker 	/* Red nodes must be interleaved with black nodes. */
89*1208bc7eSAndroid Build Coastguard Worker 	if (rbtn_red_get(node_t, link, node)) {
90*1208bc7eSAndroid Build Coastguard Worker 		if (left_node != NULL) {
91*1208bc7eSAndroid Build Coastguard Worker 			assert_false(rbtn_red_get(node_t, link, left_node),
92*1208bc7eSAndroid Build Coastguard Worker 				"Node should be black");
93*1208bc7eSAndroid Build Coastguard Worker 		}
94*1208bc7eSAndroid Build Coastguard Worker 		if (right_node != NULL) {
95*1208bc7eSAndroid Build Coastguard Worker 			assert_false(rbtn_red_get(node_t, link, right_node),
96*1208bc7eSAndroid Build Coastguard Worker 			    "Node should be black");
97*1208bc7eSAndroid Build Coastguard Worker 		}
98*1208bc7eSAndroid Build Coastguard Worker 	}
99*1208bc7eSAndroid Build Coastguard Worker 
100*1208bc7eSAndroid Build Coastguard Worker 	/* Self. */
101*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_eq(node->magic, NODE_MAGIC, "Bad magic");
102*1208bc7eSAndroid Build Coastguard Worker 
103*1208bc7eSAndroid Build Coastguard Worker 	/* Left subtree. */
104*1208bc7eSAndroid Build Coastguard Worker 	if (left_node != NULL) {
105*1208bc7eSAndroid Build Coastguard Worker 		ret += tree_recurse(left_node, black_height, black_depth);
106*1208bc7eSAndroid Build Coastguard Worker 	} else {
107*1208bc7eSAndroid Build Coastguard Worker 		ret += (black_depth != black_height);
108*1208bc7eSAndroid Build Coastguard Worker 	}
109*1208bc7eSAndroid Build Coastguard Worker 
110*1208bc7eSAndroid Build Coastguard Worker 	/* Right subtree. */
111*1208bc7eSAndroid Build Coastguard Worker 	if (right_node != NULL) {
112*1208bc7eSAndroid Build Coastguard Worker 		ret += tree_recurse(right_node, black_height, black_depth);
113*1208bc7eSAndroid Build Coastguard Worker 	} else {
114*1208bc7eSAndroid Build Coastguard Worker 		ret += (black_depth != black_height);
115*1208bc7eSAndroid Build Coastguard Worker 	}
116*1208bc7eSAndroid Build Coastguard Worker 
117*1208bc7eSAndroid Build Coastguard Worker 	return ret;
118*1208bc7eSAndroid Build Coastguard Worker }
119*1208bc7eSAndroid Build Coastguard Worker 
120*1208bc7eSAndroid Build Coastguard Worker static node_t *
tree_iterate_cb(tree_t * tree,node_t * node,void * data)121*1208bc7eSAndroid Build Coastguard Worker tree_iterate_cb(tree_t *tree, node_t *node, void *data) {
122*1208bc7eSAndroid Build Coastguard Worker 	unsigned *i = (unsigned *)data;
123*1208bc7eSAndroid Build Coastguard Worker 	node_t *search_node;
124*1208bc7eSAndroid Build Coastguard Worker 
125*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_eq(node->magic, NODE_MAGIC, "Bad magic");
126*1208bc7eSAndroid Build Coastguard Worker 
127*1208bc7eSAndroid Build Coastguard Worker 	/* Test rb_search(). */
128*1208bc7eSAndroid Build Coastguard Worker 	search_node = tree_search(tree, node);
129*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_eq(search_node, node,
130*1208bc7eSAndroid Build Coastguard Worker 	    "tree_search() returned unexpected node");
131*1208bc7eSAndroid Build Coastguard Worker 
132*1208bc7eSAndroid Build Coastguard Worker 	/* Test rb_nsearch(). */
133*1208bc7eSAndroid Build Coastguard Worker 	search_node = tree_nsearch(tree, node);
134*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_eq(search_node, node,
135*1208bc7eSAndroid Build Coastguard Worker 	    "tree_nsearch() returned unexpected node");
136*1208bc7eSAndroid Build Coastguard Worker 
137*1208bc7eSAndroid Build Coastguard Worker 	/* Test rb_psearch(). */
138*1208bc7eSAndroid Build Coastguard Worker 	search_node = tree_psearch(tree, node);
139*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_eq(search_node, node,
140*1208bc7eSAndroid Build Coastguard Worker 	    "tree_psearch() returned unexpected node");
141*1208bc7eSAndroid Build Coastguard Worker 
142*1208bc7eSAndroid Build Coastguard Worker 	(*i)++;
143*1208bc7eSAndroid Build Coastguard Worker 
144*1208bc7eSAndroid Build Coastguard Worker 	return NULL;
145*1208bc7eSAndroid Build Coastguard Worker }
146*1208bc7eSAndroid Build Coastguard Worker 
147*1208bc7eSAndroid Build Coastguard Worker static unsigned
tree_iterate(tree_t * tree)148*1208bc7eSAndroid Build Coastguard Worker tree_iterate(tree_t *tree) {
149*1208bc7eSAndroid Build Coastguard Worker 	unsigned i;
150*1208bc7eSAndroid Build Coastguard Worker 
151*1208bc7eSAndroid Build Coastguard Worker 	i = 0;
152*1208bc7eSAndroid Build Coastguard Worker 	tree_iter(tree, NULL, tree_iterate_cb, (void *)&i);
153*1208bc7eSAndroid Build Coastguard Worker 
154*1208bc7eSAndroid Build Coastguard Worker 	return i;
155*1208bc7eSAndroid Build Coastguard Worker }
156*1208bc7eSAndroid Build Coastguard Worker 
157*1208bc7eSAndroid Build Coastguard Worker static unsigned
tree_iterate_reverse(tree_t * tree)158*1208bc7eSAndroid Build Coastguard Worker tree_iterate_reverse(tree_t *tree) {
159*1208bc7eSAndroid Build Coastguard Worker 	unsigned i;
160*1208bc7eSAndroid Build Coastguard Worker 
161*1208bc7eSAndroid Build Coastguard Worker 	i = 0;
162*1208bc7eSAndroid Build Coastguard Worker 	tree_reverse_iter(tree, NULL, tree_iterate_cb, (void *)&i);
163*1208bc7eSAndroid Build Coastguard Worker 
164*1208bc7eSAndroid Build Coastguard Worker 	return i;
165*1208bc7eSAndroid Build Coastguard Worker }
166*1208bc7eSAndroid Build Coastguard Worker 
167*1208bc7eSAndroid Build Coastguard Worker static void
node_remove(tree_t * tree,node_t * node,unsigned nnodes)168*1208bc7eSAndroid Build Coastguard Worker node_remove(tree_t *tree, node_t *node, unsigned nnodes) {
169*1208bc7eSAndroid Build Coastguard Worker 	node_t *search_node;
170*1208bc7eSAndroid Build Coastguard Worker 	unsigned black_height, imbalances;
171*1208bc7eSAndroid Build Coastguard Worker 
172*1208bc7eSAndroid Build Coastguard Worker 	tree_remove(tree, node);
173*1208bc7eSAndroid Build Coastguard Worker 
174*1208bc7eSAndroid Build Coastguard Worker 	/* Test rb_nsearch(). */
175*1208bc7eSAndroid Build Coastguard Worker 	search_node = tree_nsearch(tree, node);
176*1208bc7eSAndroid Build Coastguard Worker 	if (search_node != NULL) {
177*1208bc7eSAndroid Build Coastguard Worker 		assert_u64_ge(search_node->key, node->key,
178*1208bc7eSAndroid Build Coastguard Worker 		    "Key ordering error");
179*1208bc7eSAndroid Build Coastguard Worker 	}
180*1208bc7eSAndroid Build Coastguard Worker 
181*1208bc7eSAndroid Build Coastguard Worker 	/* Test rb_psearch(). */
182*1208bc7eSAndroid Build Coastguard Worker 	search_node = tree_psearch(tree, node);
183*1208bc7eSAndroid Build Coastguard Worker 	if (search_node != NULL) {
184*1208bc7eSAndroid Build Coastguard Worker 		assert_u64_le(search_node->key, node->key,
185*1208bc7eSAndroid Build Coastguard Worker 		    "Key ordering error");
186*1208bc7eSAndroid Build Coastguard Worker 	}
187*1208bc7eSAndroid Build Coastguard Worker 
188*1208bc7eSAndroid Build Coastguard Worker 	node->magic = 0;
189*1208bc7eSAndroid Build Coastguard Worker 
190*1208bc7eSAndroid Build Coastguard Worker 	rbtn_black_height(node_t, link, tree, black_height);
191*1208bc7eSAndroid Build Coastguard Worker 	imbalances = tree_recurse(tree->rbt_root, black_height, 0);
192*1208bc7eSAndroid Build Coastguard Worker 	assert_u_eq(imbalances, 0, "Tree is unbalanced");
193*1208bc7eSAndroid Build Coastguard Worker 	assert_u_eq(tree_iterate(tree), nnodes-1,
194*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected node iteration count");
195*1208bc7eSAndroid Build Coastguard Worker 	assert_u_eq(tree_iterate_reverse(tree), nnodes-1,
196*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected node iteration count");
197*1208bc7eSAndroid Build Coastguard Worker }
198*1208bc7eSAndroid Build Coastguard Worker 
199*1208bc7eSAndroid Build Coastguard Worker static node_t *
remove_iterate_cb(tree_t * tree,node_t * node,void * data)200*1208bc7eSAndroid Build Coastguard Worker remove_iterate_cb(tree_t *tree, node_t *node, void *data) {
201*1208bc7eSAndroid Build Coastguard Worker 	unsigned *nnodes = (unsigned *)data;
202*1208bc7eSAndroid Build Coastguard Worker 	node_t *ret = tree_next(tree, node);
203*1208bc7eSAndroid Build Coastguard Worker 
204*1208bc7eSAndroid Build Coastguard Worker 	node_remove(tree, node, *nnodes);
205*1208bc7eSAndroid Build Coastguard Worker 
206*1208bc7eSAndroid Build Coastguard Worker 	return ret;
207*1208bc7eSAndroid Build Coastguard Worker }
208*1208bc7eSAndroid Build Coastguard Worker 
209*1208bc7eSAndroid Build Coastguard Worker static node_t *
remove_reverse_iterate_cb(tree_t * tree,node_t * node,void * data)210*1208bc7eSAndroid Build Coastguard Worker remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data) {
211*1208bc7eSAndroid Build Coastguard Worker 	unsigned *nnodes = (unsigned *)data;
212*1208bc7eSAndroid Build Coastguard Worker 	node_t *ret = tree_prev(tree, node);
213*1208bc7eSAndroid Build Coastguard Worker 
214*1208bc7eSAndroid Build Coastguard Worker 	node_remove(tree, node, *nnodes);
215*1208bc7eSAndroid Build Coastguard Worker 
216*1208bc7eSAndroid Build Coastguard Worker 	return ret;
217*1208bc7eSAndroid Build Coastguard Worker }
218*1208bc7eSAndroid Build Coastguard Worker 
219*1208bc7eSAndroid Build Coastguard Worker static void
destroy_cb(node_t * node,void * data)220*1208bc7eSAndroid Build Coastguard Worker destroy_cb(node_t *node, void *data) {
221*1208bc7eSAndroid Build Coastguard Worker 	unsigned *nnodes = (unsigned *)data;
222*1208bc7eSAndroid Build Coastguard Worker 
223*1208bc7eSAndroid Build Coastguard Worker 	assert_u_gt(*nnodes, 0, "Destruction removed too many nodes");
224*1208bc7eSAndroid Build Coastguard Worker 	(*nnodes)--;
225*1208bc7eSAndroid Build Coastguard Worker }
226*1208bc7eSAndroid Build Coastguard Worker 
TEST_BEGIN(test_rb_random)227*1208bc7eSAndroid Build Coastguard Worker TEST_BEGIN(test_rb_random) {
228*1208bc7eSAndroid Build Coastguard Worker #define NNODES 25
229*1208bc7eSAndroid Build Coastguard Worker #define NBAGS 250
230*1208bc7eSAndroid Build Coastguard Worker #define SEED 42
231*1208bc7eSAndroid Build Coastguard Worker 	sfmt_t *sfmt;
232*1208bc7eSAndroid Build Coastguard Worker 	uint64_t bag[NNODES];
233*1208bc7eSAndroid Build Coastguard Worker 	tree_t tree;
234*1208bc7eSAndroid Build Coastguard Worker 	node_t nodes[NNODES];
235*1208bc7eSAndroid Build Coastguard Worker 	unsigned i, j, k, black_height, imbalances;
236*1208bc7eSAndroid Build Coastguard Worker 
237*1208bc7eSAndroid Build Coastguard Worker 	sfmt = init_gen_rand(SEED);
238*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < NBAGS; i++) {
239*1208bc7eSAndroid Build Coastguard Worker 		switch (i) {
240*1208bc7eSAndroid Build Coastguard Worker 		case 0:
241*1208bc7eSAndroid Build Coastguard Worker 			/* Insert in order. */
242*1208bc7eSAndroid Build Coastguard Worker 			for (j = 0; j < NNODES; j++) {
243*1208bc7eSAndroid Build Coastguard Worker 				bag[j] = j;
244*1208bc7eSAndroid Build Coastguard Worker 			}
245*1208bc7eSAndroid Build Coastguard Worker 			break;
246*1208bc7eSAndroid Build Coastguard Worker 		case 1:
247*1208bc7eSAndroid Build Coastguard Worker 			/* Insert in reverse order. */
248*1208bc7eSAndroid Build Coastguard Worker 			for (j = 0; j < NNODES; j++) {
249*1208bc7eSAndroid Build Coastguard Worker 				bag[j] = NNODES - j - 1;
250*1208bc7eSAndroid Build Coastguard Worker 			}
251*1208bc7eSAndroid Build Coastguard Worker 			break;
252*1208bc7eSAndroid Build Coastguard Worker 		default:
253*1208bc7eSAndroid Build Coastguard Worker 			for (j = 0; j < NNODES; j++) {
254*1208bc7eSAndroid Build Coastguard Worker 				bag[j] = gen_rand64_range(sfmt, NNODES);
255*1208bc7eSAndroid Build Coastguard Worker 			}
256*1208bc7eSAndroid Build Coastguard Worker 		}
257*1208bc7eSAndroid Build Coastguard Worker 
258*1208bc7eSAndroid Build Coastguard Worker 		for (j = 1; j <= NNODES; j++) {
259*1208bc7eSAndroid Build Coastguard Worker 			/* Initialize tree and nodes. */
260*1208bc7eSAndroid Build Coastguard Worker 			tree_new(&tree);
261*1208bc7eSAndroid Build Coastguard Worker 			for (k = 0; k < j; k++) {
262*1208bc7eSAndroid Build Coastguard Worker 				nodes[k].magic = NODE_MAGIC;
263*1208bc7eSAndroid Build Coastguard Worker 				nodes[k].key = bag[k];
264*1208bc7eSAndroid Build Coastguard Worker 			}
265*1208bc7eSAndroid Build Coastguard Worker 
266*1208bc7eSAndroid Build Coastguard Worker 			/* Insert nodes. */
267*1208bc7eSAndroid Build Coastguard Worker 			for (k = 0; k < j; k++) {
268*1208bc7eSAndroid Build Coastguard Worker 				tree_insert(&tree, &nodes[k]);
269*1208bc7eSAndroid Build Coastguard Worker 
270*1208bc7eSAndroid Build Coastguard Worker 				rbtn_black_height(node_t, link, &tree,
271*1208bc7eSAndroid Build Coastguard Worker 				    black_height);
272*1208bc7eSAndroid Build Coastguard Worker 				imbalances = tree_recurse(tree.rbt_root,
273*1208bc7eSAndroid Build Coastguard Worker 				    black_height, 0);
274*1208bc7eSAndroid Build Coastguard Worker 				assert_u_eq(imbalances, 0,
275*1208bc7eSAndroid Build Coastguard Worker 				    "Tree is unbalanced");
276*1208bc7eSAndroid Build Coastguard Worker 
277*1208bc7eSAndroid Build Coastguard Worker 				assert_u_eq(tree_iterate(&tree), k+1,
278*1208bc7eSAndroid Build Coastguard Worker 				    "Unexpected node iteration count");
279*1208bc7eSAndroid Build Coastguard Worker 				assert_u_eq(tree_iterate_reverse(&tree), k+1,
280*1208bc7eSAndroid Build Coastguard Worker 				    "Unexpected node iteration count");
281*1208bc7eSAndroid Build Coastguard Worker 
282*1208bc7eSAndroid Build Coastguard Worker 				assert_false(tree_empty(&tree),
283*1208bc7eSAndroid Build Coastguard Worker 				    "Tree should not be empty");
284*1208bc7eSAndroid Build Coastguard Worker 				assert_ptr_not_null(tree_first(&tree),
285*1208bc7eSAndroid Build Coastguard Worker 				    "Tree should not be empty");
286*1208bc7eSAndroid Build Coastguard Worker 				assert_ptr_not_null(tree_last(&tree),
287*1208bc7eSAndroid Build Coastguard Worker 				    "Tree should not be empty");
288*1208bc7eSAndroid Build Coastguard Worker 
289*1208bc7eSAndroid Build Coastguard Worker 				tree_next(&tree, &nodes[k]);
290*1208bc7eSAndroid Build Coastguard Worker 				tree_prev(&tree, &nodes[k]);
291*1208bc7eSAndroid Build Coastguard Worker 			}
292*1208bc7eSAndroid Build Coastguard Worker 
293*1208bc7eSAndroid Build Coastguard Worker 			/* Remove nodes. */
294*1208bc7eSAndroid Build Coastguard Worker 			switch (i % 5) {
295*1208bc7eSAndroid Build Coastguard Worker 			case 0:
296*1208bc7eSAndroid Build Coastguard Worker 				for (k = 0; k < j; k++) {
297*1208bc7eSAndroid Build Coastguard Worker 					node_remove(&tree, &nodes[k], j - k);
298*1208bc7eSAndroid Build Coastguard Worker 				}
299*1208bc7eSAndroid Build Coastguard Worker 				break;
300*1208bc7eSAndroid Build Coastguard Worker 			case 1:
301*1208bc7eSAndroid Build Coastguard Worker 				for (k = j; k > 0; k--) {
302*1208bc7eSAndroid Build Coastguard Worker 					node_remove(&tree, &nodes[k-1], k);
303*1208bc7eSAndroid Build Coastguard Worker 				}
304*1208bc7eSAndroid Build Coastguard Worker 				break;
305*1208bc7eSAndroid Build Coastguard Worker 			case 2: {
306*1208bc7eSAndroid Build Coastguard Worker 				node_t *start;
307*1208bc7eSAndroid Build Coastguard Worker 				unsigned nnodes = j;
308*1208bc7eSAndroid Build Coastguard Worker 
309*1208bc7eSAndroid Build Coastguard Worker 				start = NULL;
310*1208bc7eSAndroid Build Coastguard Worker 				do {
311*1208bc7eSAndroid Build Coastguard Worker 					start = tree_iter(&tree, start,
312*1208bc7eSAndroid Build Coastguard Worker 					    remove_iterate_cb, (void *)&nnodes);
313*1208bc7eSAndroid Build Coastguard Worker 					nnodes--;
314*1208bc7eSAndroid Build Coastguard Worker 				} while (start != NULL);
315*1208bc7eSAndroid Build Coastguard Worker 				assert_u_eq(nnodes, 0,
316*1208bc7eSAndroid Build Coastguard Worker 				    "Removal terminated early");
317*1208bc7eSAndroid Build Coastguard Worker 				break;
318*1208bc7eSAndroid Build Coastguard Worker 			} case 3: {
319*1208bc7eSAndroid Build Coastguard Worker 				node_t *start;
320*1208bc7eSAndroid Build Coastguard Worker 				unsigned nnodes = j;
321*1208bc7eSAndroid Build Coastguard Worker 
322*1208bc7eSAndroid Build Coastguard Worker 				start = NULL;
323*1208bc7eSAndroid Build Coastguard Worker 				do {
324*1208bc7eSAndroid Build Coastguard Worker 					start = tree_reverse_iter(&tree, start,
325*1208bc7eSAndroid Build Coastguard Worker 					    remove_reverse_iterate_cb,
326*1208bc7eSAndroid Build Coastguard Worker 					    (void *)&nnodes);
327*1208bc7eSAndroid Build Coastguard Worker 					nnodes--;
328*1208bc7eSAndroid Build Coastguard Worker 				} while (start != NULL);
329*1208bc7eSAndroid Build Coastguard Worker 				assert_u_eq(nnodes, 0,
330*1208bc7eSAndroid Build Coastguard Worker 				    "Removal terminated early");
331*1208bc7eSAndroid Build Coastguard Worker 				break;
332*1208bc7eSAndroid Build Coastguard Worker 			} case 4: {
333*1208bc7eSAndroid Build Coastguard Worker 				unsigned nnodes = j;
334*1208bc7eSAndroid Build Coastguard Worker 				tree_destroy(&tree, destroy_cb, &nnodes);
335*1208bc7eSAndroid Build Coastguard Worker 				assert_u_eq(nnodes, 0,
336*1208bc7eSAndroid Build Coastguard Worker 				    "Destruction terminated early");
337*1208bc7eSAndroid Build Coastguard Worker 				break;
338*1208bc7eSAndroid Build Coastguard Worker 			} default:
339*1208bc7eSAndroid Build Coastguard Worker 				not_reached();
340*1208bc7eSAndroid Build Coastguard Worker 			}
341*1208bc7eSAndroid Build Coastguard Worker 		}
342*1208bc7eSAndroid Build Coastguard Worker 	}
343*1208bc7eSAndroid Build Coastguard Worker 	fini_gen_rand(sfmt);
344*1208bc7eSAndroid Build Coastguard Worker #undef NNODES
345*1208bc7eSAndroid Build Coastguard Worker #undef NBAGS
346*1208bc7eSAndroid Build Coastguard Worker #undef SEED
347*1208bc7eSAndroid Build Coastguard Worker }
348*1208bc7eSAndroid Build Coastguard Worker TEST_END
349*1208bc7eSAndroid Build Coastguard Worker 
350*1208bc7eSAndroid Build Coastguard Worker int
main(void)351*1208bc7eSAndroid Build Coastguard Worker main(void) {
352*1208bc7eSAndroid Build Coastguard Worker 	return test(
353*1208bc7eSAndroid Build Coastguard Worker 	    test_rb_empty,
354*1208bc7eSAndroid Build Coastguard Worker 	    test_rb_random);
355*1208bc7eSAndroid Build Coastguard Worker }
356