Improve SSH2 host key abstraction into a generic `signing key'
[u/mdw/putty] / tree234.c
CommitLineData
febd9a0f 1/*
2 * tree234.c: reasonably generic 2-3-4 tree routines. Currently
3 * supports insert, delete, find and iterate operations.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "tree234.h"
10
11#define mknew(typ) ( (typ *) malloc (sizeof (typ)) )
12#define sfree free
13
14#ifdef TEST
15#define LOG(x) (printf x)
16#else
17#define LOG(x)
18#endif
19
20struct tree234_Tag {
21 node234 *root;
22 cmpfn234 cmp;
23};
24
25struct node234_Tag {
26 node234 *parent;
27 node234 *kids[4];
28 void *elems[3];
29};
30
31/*
32 * Create a 2-3-4 tree.
33 */
34tree234 *newtree234(cmpfn234 cmp) {
35 tree234 *ret = mknew(tree234);
36 LOG(("created tree %p\n", ret));
37 ret->root = NULL;
38 ret->cmp = cmp;
39 return ret;
40}
41
42/*
43 * Free a 2-3-4 tree (not including freeing the elements).
44 */
45static void freenode234(node234 *n) {
46 if (!n)
47 return;
48 freenode234(n->kids[0]);
49 freenode234(n->kids[1]);
50 freenode234(n->kids[2]);
51 freenode234(n->kids[3]);
52 sfree(n);
53}
54void freetree234(tree234 *t) {
55 freenode234(t->root);
56 sfree(t);
57}
58
59/*
60 * Add an element e to a 2-3-4 tree t. Returns e on success, or if
61 * an existing element compares equal, returns that.
62 */
63void *add234(tree234 *t, void *e) {
64 node234 *n, **np, *left, *right;
65 void *orig_e = e;
66 int c;
67
68 LOG(("adding node %p to tree %p\n", e, t));
69 if (t->root == NULL) {
70 t->root = mknew(node234);
71 t->root->elems[1] = t->root->elems[2] = NULL;
72 t->root->kids[0] = t->root->kids[1] = NULL;
73 t->root->kids[2] = t->root->kids[3] = NULL;
74 t->root->parent = NULL;
75 t->root->elems[0] = e;
76 LOG((" created root %p\n", t->root));
77 return orig_e;
78 }
79
80 np = &t->root;
81 while (*np) {
82 n = *np;
83 LOG((" node %p: %p [%p] %p [%p] %p [%p] %p\n",
84 n, n->kids[0], n->elems[0], n->kids[1], n->elems[1],
85 n->kids[2], n->elems[2], n->kids[3]));
86 if ((c = t->cmp(e, n->elems[0])) < 0)
87 np = &n->kids[0];
88 else if (c == 0)
89 return n->elems[0]; /* already exists */
90 else if (n->elems[1] == NULL || (c = t->cmp(e, n->elems[1])) < 0)
91 np = &n->kids[1];
92 else if (c == 0)
93 return n->elems[1]; /* already exists */
94 else if (n->elems[2] == NULL || (c = t->cmp(e, n->elems[2])) < 0)
95 np = &n->kids[2];
96 else if (c == 0)
97 return n->elems[2]; /* already exists */
98 else
99 np = &n->kids[3];
100 LOG((" moving to child %d (%p)\n", np - n->kids, *np));
101 }
102
103 /*
104 * We need to insert the new element in n at position np.
105 */
106 left = NULL;
107 right = NULL;
108 while (n) {
109 LOG((" at %p: %p [%p] %p [%p] %p [%p] %p\n",
110 n, n->kids[0], n->elems[0], n->kids[1], n->elems[1],
111 n->kids[2], n->elems[2], n->kids[3]));
112 LOG((" need to insert %p [%p] %p at position %d\n",
113 left, e, right, np - n->kids));
114 if (n->elems[1] == NULL) {
115 /*
116 * Insert in a 2-node; simple.
117 */
118 if (np == &n->kids[0]) {
119 LOG((" inserting on left of 2-node\n"));
120 n->kids[2] = n->kids[1];
121 n->elems[1] = n->elems[0];
122 n->kids[1] = right;
123 n->elems[0] = e;
124 n->kids[0] = left;
125 } else { /* np == &n->kids[1] */
126 LOG((" inserting on right of 2-node\n"));
127 n->kids[2] = right;
128 n->elems[1] = e;
129 n->kids[1] = left;
130 }
131 if (n->kids[0]) n->kids[0]->parent = n;
132 if (n->kids[1]) n->kids[1]->parent = n;
133 if (n->kids[2]) n->kids[2]->parent = n;
134 LOG((" done\n"));
135 break;
136 } else if (n->elems[2] == NULL) {
137 /*
138 * Insert in a 3-node; simple.
139 */
140 if (np == &n->kids[0]) {
141 LOG((" inserting on left of 3-node\n"));
142 n->kids[3] = n->kids[2];
143 n->elems[2] = n->elems[1];
144 n->kids[2] = n->kids[1];
145 n->elems[1] = n->elems[0];
146 n->kids[1] = right;
147 n->elems[0] = e;
148 n->kids[0] = left;
149 } else if (np == &n->kids[1]) {
150 LOG((" inserting in middle of 3-node\n"));
151 n->kids[3] = n->kids[2];
152 n->elems[2] = n->elems[1];
153 n->kids[2] = right;
154 n->elems[1] = e;
155 n->kids[1] = left;
156 } else { /* np == &n->kids[2] */
157 LOG((" inserting on right of 3-node\n"));
158 n->kids[3] = right;
159 n->elems[2] = e;
160 n->kids[2] = left;
161 }
162 if (n->kids[0]) n->kids[0]->parent = n;
163 if (n->kids[1]) n->kids[1]->parent = n;
164 if (n->kids[2]) n->kids[2]->parent = n;
165 if (n->kids[3]) n->kids[3]->parent = n;
166 LOG((" done\n"));
167 break;
168 } else {
169 node234 *m = mknew(node234);
170 m->parent = n->parent;
171 LOG((" splitting a 4-node; created new node %p\n", m));
172 /*
173 * Insert in a 4-node; split into a 2-node and a
174 * 3-node, and move focus up a level.
175 *
176 * I don't think it matters which way round we put the
177 * 2 and the 3. For simplicity, we'll put the 3 first
178 * always.
179 */
180 if (np == &n->kids[0]) {
181 m->kids[0] = left;
182 m->elems[0] = e;
183 m->kids[1] = right;
184 m->elems[1] = n->elems[0];
185 m->kids[2] = n->kids[1];
186 e = n->elems[1];
187 n->kids[0] = n->kids[2];
188 n->elems[0] = n->elems[2];
189 n->kids[1] = n->kids[3];
190 } else if (np == &n->kids[1]) {
191 m->kids[0] = n->kids[0];
192 m->elems[0] = n->elems[0];
193 m->kids[1] = left;
194 m->elems[1] = e;
195 m->kids[2] = right;
196 e = n->elems[1];
197 n->kids[0] = n->kids[2];
198 n->elems[0] = n->elems[2];
199 n->kids[1] = n->kids[3];
200 } else if (np == &n->kids[2]) {
201 m->kids[0] = n->kids[0];
202 m->elems[0] = n->elems[0];
203 m->kids[1] = n->kids[1];
204 m->elems[1] = n->elems[1];
205 m->kids[2] = left;
206 /* e = e; */
207 n->kids[0] = right;
208 n->elems[0] = n->elems[2];
209 n->kids[1] = n->kids[3];
210 } else { /* np == &n->kids[3] */
211 m->kids[0] = n->kids[0];
212 m->elems[0] = n->elems[0];
213 m->kids[1] = n->kids[1];
214 m->elems[1] = n->elems[1];
215 m->kids[2] = n->kids[2];
216 n->kids[0] = left;
217 n->elems[0] = e;
218 n->kids[1] = right;
219 e = n->elems[2];
220 }
221 m->kids[3] = n->kids[3] = n->kids[2] = NULL;
222 m->elems[2] = n->elems[2] = n->elems[1] = NULL;
223 if (m->kids[0]) m->kids[0]->parent = m;
224 if (m->kids[1]) m->kids[1]->parent = m;
225 if (m->kids[2]) m->kids[2]->parent = m;
226 if (n->kids[0]) n->kids[0]->parent = n;
227 if (n->kids[1]) n->kids[1]->parent = n;
228 LOG((" left (%p): %p [%p] %p [%p] %p\n", m,
229 m->kids[0], m->elems[0],
230 m->kids[1], m->elems[1],
231 m->kids[2]));
232 LOG((" right (%p): %p [%p] %p\n", n,
233 n->kids[0], n->elems[0],
234 n->kids[1]));
235 left = m;
236 right = n;
237 }
238 if (n->parent)
239 np = (n->parent->kids[0] == n ? &n->parent->kids[0] :
240 n->parent->kids[1] == n ? &n->parent->kids[1] :
241 n->parent->kids[2] == n ? &n->parent->kids[2] :
242 &n->parent->kids[3]);
243 n = n->parent;
244 }
245
246 /*
247 * If we've come out of here by `break', n will still be
248 * non-NULL and we've finished. If we've come here because n is
249 * NULL, we need to create a new root for the tree because the
250 * old one has just split into two.
251 */
252 if (!n) {
253 LOG((" root is overloaded, split into two\n"));
254 t->root = mknew(node234);
255 t->root->kids[0] = left;
256 t->root->elems[0] = e;
257 t->root->kids[1] = right;
258 t->root->elems[1] = NULL;
259 t->root->kids[2] = NULL;
260 t->root->elems[2] = NULL;
261 t->root->kids[3] = NULL;
262 t->root->parent = NULL;
263 if (t->root->kids[0]) t->root->kids[0]->parent = t->root;
264 if (t->root->kids[1]) t->root->kids[1]->parent = t->root;
265 LOG((" new root is %p [%p] %p\n",
266 t->root->kids[0], t->root->elems[0], t->root->kids[1]));
267 }
268
269 return orig_e;
270}
271
272/*
273 * Find an element e in a 2-3-4 tree t. Returns NULL if not found.
274 * e is always passed as the first argument to cmp, so cmp can be
275 * an asymmetric function if desired. cmp can also be passed as
276 * NULL, in which case the compare function from the tree proper
277 * will be used.
278 */
279void *find234(tree234 *t, void *e, cmpfn234 cmp) {
280 node234 *n;
281 int c;
282
283 if (t->root == NULL)
284 return NULL;
285
286 if (cmp == NULL)
287 cmp = t->cmp;
288
289 n = t->root;
290 while (n) {
81d77872 291 if ( (c = cmp(e, n->elems[0])) < 0)
febd9a0f 292 n = n->kids[0];
293 else if (c == 0)
294 return n->elems[0];
81d77872 295 else if (n->elems[1] == NULL || (c = cmp(e, n->elems[1])) < 0)
febd9a0f 296 n = n->kids[1];
297 else if (c == 0)
298 return n->elems[1];
81d77872 299 else if (n->elems[2] == NULL || (c = cmp(e, n->elems[2])) < 0)
febd9a0f 300 n = n->kids[2];
301 else if (c == 0)
302 return n->elems[2];
303 else
304 n = n->kids[3];
305 }
306
307 /*
308 * We've found our way to the bottom of the tree and we know
309 * where we would insert this node if we wanted to. But it
310 * isn't there.
311 */
312 return NULL;
313}
314
315/*
316 * Delete an element e in a 2-3-4 tree. Does not free the element,
317 * merely removes all links to it from the tree nodes.
318 */
81d77872 319void del234(tree234 *t, void *e) {
febd9a0f 320 node234 *n;
321 int ei = -1;
322
323 n = t->root;
324 LOG(("deleting %p from tree %p\n", e, t));
325 while (1) {
326 while (n) {
327 int c;
328 int ki;
329 node234 *sub;
330
331 LOG((" node %p: %p [%p] %p [%p] %p [%p] %p\n",
332 n, n->kids[0], n->elems[0], n->kids[1], n->elems[1],
333 n->kids[2], n->elems[2], n->kids[3]));
334 if ((c = t->cmp(e, n->elems[0])) < 0) {
335 ki = 0;
336 } else if (c == 0) {
337 ei = 0; break;
338 } else if (n->elems[1] == NULL || (c = t->cmp(e, n->elems[1])) < 0) {
339 ki = 1;
340 } else if (c == 0) {
341 ei = 1; break;
342 } else if (n->elems[2] == NULL || (c = t->cmp(e, n->elems[2])) < 0) {
343 ki = 2;
344 } else if (c == 0) {
345 ei = 2; break;
346 } else {
347 ki = 3;
348 }
349 /*
350 * Recurse down to subtree ki. If it has only one element,
351 * we have to do some transformation to start with.
352 */
353 LOG((" moving to subtree %d\n", ki));
354 sub = n->kids[ki];
355 if (!sub->elems[1]) {
356 LOG((" subtree has only one element!\n", ki));
357 if (ki > 0 && n->kids[ki-1]->elems[1]) {
358 /*
359 * Case 3a, left-handed variant. Child ki has
360 * only one element, but child ki-1 has two or
361 * more. So we need to move a subtree from ki-1
362 * to ki.
363 *
364 * . C . . B .
365 * / \ -> / \
366 * [more] a A b B c d D e [more] a A b c C d D e
367 */
368 node234 *sib = n->kids[ki-1];
369 int lastelem = (sib->elems[2] ? 2 :
370 sib->elems[1] ? 1 : 0);
371 sub->kids[2] = sub->kids[1];
372 sub->elems[1] = sub->elems[0];
373 sub->kids[1] = sub->kids[0];
374 sub->elems[0] = n->elems[ki-1];
375 sub->kids[0] = sib->kids[lastelem+1];
100122a9 376 if (sub->kids[0]) sub->kids[0]->parent = sub;
febd9a0f 377 n->elems[ki-1] = sib->elems[lastelem];
378 sib->kids[lastelem+1] = NULL;
379 sib->elems[lastelem] = NULL;
380 LOG((" case 3a left\n"));
381 } else if (ki < 3 && n->kids[ki+1] &&
382 n->kids[ki+1]->elems[1]) {
383 /*
384 * Case 3a, right-handed variant. ki has only
385 * one element but ki+1 has two or more. Move a
386 * subtree from ki+1 to ki.
387 *
388 * . B . . C .
389 * / \ -> / \
390 * a A b c C d D e [more] a A b B c d D e [more]
391 */
392 node234 *sib = n->kids[ki+1];
393 int j;
394 sub->elems[1] = n->elems[ki];
395 sub->kids[2] = sib->kids[0];
100122a9 396 if (sub->kids[2]) sub->kids[2]->parent = sub;
febd9a0f 397 n->elems[ki] = sib->elems[0];
398 sib->kids[0] = sib->kids[1];
399 for (j = 0; j < 2 && sib->elems[j+1]; j++) {
400 sib->kids[j+1] = sib->kids[j+2];
401 sib->elems[j] = sib->elems[j+1];
402 }
403 sib->kids[j+1] = NULL;
404 sib->elems[j] = NULL;
405 LOG((" case 3a right\n"));
406 } else {
407 /*
408 * Case 3b. ki has only one element, and has no
409 * neighbour with more than one. So pick a
410 * neighbour and merge it with ki, taking an
411 * element down from n to go in the middle.
412 *
413 * . B . .
414 * / \ -> |
415 * a A b c C d a A b B c C d
416 *
417 * (Since at all points we have avoided
418 * descending to a node with only one element,
419 * we can be sure that n is not reduced to
420 * nothingness by this move, _unless_ it was
421 * the very first node, ie the root of the
422 * tree. In that case we remove the now-empty
423 * root and replace it with its single large
424 * child as shown.)
425 */
426 node234 *sib;
427 int j;
428
429 if (ki > 0)
430 ki--;
431 sib = n->kids[ki];
432 sub = n->kids[ki+1];
433
434 sub->kids[3] = sub->kids[1];
435 sub->elems[2] = sub->elems[0];
436 sub->kids[2] = sub->kids[0];
437 sub->elems[1] = n->elems[ki];
438 sub->kids[1] = sib->kids[1];
100122a9 439 if (sub->kids[1]) sub->kids[1]->parent = sub;
febd9a0f 440 sub->elems[0] = sib->elems[0];
441 sub->kids[0] = sib->kids[0];
100122a9 442 if (sub->kids[0]) sub->kids[0]->parent = sub;
febd9a0f 443
444 sfree(sib);
445
446 /*
447 * That's built the big node in sub. Now we
448 * need to remove the reference to sib in n.
449 */
450 for (j = ki; j < 3 && n->kids[j+1]; j++) {
451 n->kids[j] = n->kids[j+1];
452 n->elems[j] = j<2 ? n->elems[j+1] : NULL;
453 }
454 n->kids[j] = NULL;
455 if (j < 3) n->elems[j] = NULL;
2d56b16f 456 LOG((" case 3b ki=%d\n", ki));
febd9a0f 457
458 if (!n->elems[0]) {
459 /*
460 * The root is empty and needs to be
461 * removed.
462 */
463 LOG((" shifting root!\n"));
464 t->root = sub;
465 sub->parent = NULL;
466 sfree(n);
467 }
468 }
469 }
470 n = sub;
471 }
472 if (ei==-1)
473 return; /* nothing to do; `already removed' */
474
475 /*
476 * Treat special case: this is the one remaining item in
477 * the tree. n is the tree root (no parent), has one
478 * element (no elems[1]), and has no kids (no kids[0]).
479 */
480 if (!n->parent && !n->elems[1] && !n->kids[0]) {
481 LOG((" removed last element in tree\n"));
482 sfree(n);
483 t->root = NULL;
484 return;
485 }
486
487 /*
488 * Now we have the element we want, as n->elems[ei], and we
489 * have also arranged for that element not to be the only
490 * one in its node. So...
491 */
492
493 if (!n->kids[0] && n->elems[1]) {
494 /*
495 * Case 1. n is a leaf node with more than one element,
496 * so it's _really easy_. Just delete the thing and
497 * we're done.
498 */
499 int i;
500 LOG((" case 1\n"));
a4a19e73 501 for (i = ei; i < 2 && n->elems[i+1]; i++)
febd9a0f 502 n->elems[i] = n->elems[i+1];
503 n->elems[i] = NULL;
504 return; /* finished! */
505 } else if (n->kids[ei]->elems[1]) {
506 /*
507 * Case 2a. n is an internal node, and the root of the
508 * subtree to the left of e has more than one element.
509 * So find the predecessor p to e (ie the largest node
510 * in that subtree), place it where e currently is, and
511 * then start the deletion process over again on the
512 * subtree with p as target.
513 */
514 node234 *m = n->kids[ei];
515 void *target;
516 LOG((" case 2a\n"));
517 while (m->kids[0]) {
518 m = (m->kids[3] ? m->kids[3] :
519 m->kids[2] ? m->kids[2] :
520 m->kids[1] ? m->kids[1] : m->kids[0]);
521 }
522 target = (m->elems[2] ? m->elems[2] :
523 m->elems[1] ? m->elems[1] : m->elems[0]);
524 n->elems[ei] = target;
525 n = n->kids[ei];
526 e = target;
527 } else if (n->kids[ei+1]->elems[1]) {
528 /*
529 * Case 2b, symmetric to 2a but s/left/right/ and
530 * s/predecessor/successor/. (And s/largest/smallest/).
531 */
532 node234 *m = n->kids[ei+1];
533 void *target;
534 LOG((" case 2b\n"));
535 while (m->kids[0]) {
536 m = m->kids[0];
537 }
538 target = m->elems[0];
539 n->elems[ei] = target;
540 n = n->kids[ei+1];
541 e = target;
542 } else {
543 /*
544 * Case 2c. n is an internal node, and the subtrees to
545 * the left and right of e both have only one element.
546 * So combine the two subnodes into a single big node
547 * with their own elements on the left and right and e
548 * in the middle, then restart the deletion process on
549 * that subtree, with e still as target.
550 */
551 node234 *a = n->kids[ei], *b = n->kids[ei+1];
552 int j;
553
554 LOG((" case 2c\n"));
555 a->elems[1] = n->elems[ei];
556 a->kids[2] = b->kids[0];
100122a9 557 if (a->kids[2]) a->kids[2]->parent = a;
febd9a0f 558 a->elems[2] = b->elems[0];
559 a->kids[3] = b->kids[1];
100122a9 560 if (a->kids[3]) a->kids[3]->parent = a;
febd9a0f 561 sfree(b);
562 /*
563 * That's built the big node in a, and destroyed b. Now
564 * remove the reference to b (and e) in n.
565 */
566 for (j = ei; j < 2 && n->elems[j+1]; j++) {
567 n->elems[j] = n->elems[j+1];
568 n->kids[j+1] = n->kids[j+2];
569 }
570 n->elems[j] = NULL;
571 n->kids[j+1] = NULL;
e9e9556d 572 /*
573 * It's possible, in this case, that we've just removed
574 * the only element in the root of the tree. If so,
575 * shift the root.
576 */
577 if (n->elems[0] == NULL) {
578 LOG((" shifting root!\n"));
579 t->root = a;
580 a->parent = NULL;
581 sfree(n);
582 }
febd9a0f 583 /*
584 * Now go round the deletion process again, with n
585 * pointing at the new big node and e still the same.
586 */
587 n = a;
588 }
589 }
590}
591
592/*
593 * Iterate over the elements of a tree234, in order.
594 */
595void *first234(tree234 *t, enum234 *e) {
596 node234 *n = t->root;
597 if (!n)
598 return NULL;
599 while (n->kids[0])
600 n = n->kids[0];
601 e->node = n;
602 e->posn = 0;
603 return n->elems[0];
604}
605
606void *next234(enum234 *e) {
607 node234 *n = e->node;
608 int pos = e->posn;
609
610 if (n->kids[pos+1]) {
611 n = n->kids[pos+1];
612 while (n->kids[0])
613 n = n->kids[0];
614 e->node = n;
615 e->posn = 0;
616 return n->elems[0];
617 }
618
6aff1005 619 if (pos < 2 && n->elems[pos+1]) {
620 e->posn = pos+1;
621 return n->elems[e->posn];
febd9a0f 622 }
623
624 do {
625 node234 *nn = n->parent;
626 if (nn == NULL)
627 return NULL; /* end of tree */
628 pos = (nn->kids[0] == n ? 0 :
629 nn->kids[1] == n ? 1 :
630 nn->kids[2] == n ? 2 : 3);
631 n = nn;
632 } while (pos == 3 || n->kids[pos+1] == NULL);
633
634 e->node = n;
635 e->posn = pos;
636 return n->elems[pos];
637}
638
639#ifdef TEST
640
2d56b16f 641/*
642 * Test code for the 2-3-4 tree. This code maintains an alternative
643 * representation of the data in the tree, in an array (using the
644 * obvious and slow insert and delete functions). After each tree
7aa7c43a 645 * operation, the verify() function is called, which ensures all
646 * the tree properties are preserved (node->child->parent always
647 * equals node; number of kids == 0 or number of elements + 1;
648 * ordering property between elements of a node and elements of its
649 * children is preserved; tree has the same depth everywhere; every
650 * node has at least one element) and also ensures the list
651 * represented by the tree is the same list it should be. (This
652 * last check also verifies the ordering properties, because the
653 * `same list it should be' is by definition correctly ordered. It
654 * also ensures all nodes are distinct, because the enum functions
655 * would get caught in a loop if not.)
2d56b16f 656 */
657
658#include <stdarg.h>
659
660/*
661 * Error reporting function.
662 */
663void error(char *fmt, ...) {
664 va_list ap;
665 printf("ERROR: ");
666 va_start(ap, fmt);
667 vfprintf(stdout, fmt, ap);
668 va_end(ap);
669 printf("\n");
670}
671
672/* The array representation of the data. */
673void **array;
674int arraylen, arraysize;
675cmpfn234 cmp;
676
677/* The tree representation of the same data. */
678tree234 *tree;
679
680typedef struct {
681 int treedepth;
682 int elemcount;
683} chkctx;
684
685void chknode(chkctx *ctx, int level, node234 *node,
686 void *lowbound, void *highbound) {
687 int nkids, nelems;
688 int i;
689
690 /* Count the non-NULL kids. */
691 for (nkids = 0; nkids < 4 && node->kids[nkids]; nkids++);
692 /* Ensure no kids beyond the first NULL are non-NULL. */
693 for (i = nkids; i < 4; i++)
694 if (node->kids[i]) {
695 error("node %p: nkids=%d but kids[%d] non-NULL",
696 node, nkids, i);
697 }
698
699 /* Count the non-NULL elements. */
700 for (nelems = 0; nelems < 3 && node->elems[nelems]; nelems++);
701 /* Ensure no elements beyond the first NULL are non-NULL. */
702 for (i = nelems; i < 3; i++)
703 if (node->elems[i]) {
704 error("node %p: nelems=%d but elems[%d] non-NULL",
705 node, nelems, i);
706 }
707
708 if (nkids == 0) {
709 /*
710 * If nkids==0, this is a leaf node; verify that the tree
711 * depth is the same everywhere.
712 */
713 if (ctx->treedepth < 0)
714 ctx->treedepth = level; /* we didn't know the depth yet */
715 else if (ctx->treedepth != level)
716 error("node %p: leaf at depth %d, previously seen depth %d",
717 node, level, ctx->treedepth);
718 } else {
719 /*
720 * If nkids != 0, then it should be nelems+1, unless nelems
721 * is 0 in which case nkids should also be 0 (and so we
722 * shouldn't be in this condition at all).
723 */
724 int shouldkids = (nelems ? nelems+1 : 0);
725 if (nkids != shouldkids) {
726 error("node %p: %d elems should mean %d kids but has %d",
727 node, nelems, shouldkids, nkids);
728 }
729 }
730
731 /*
732 * nelems should be at least 1.
733 */
734 if (nelems == 0) {
735 error("node %p: no elems", node, nkids);
736 }
737
738 /*
739 * Add nelems to the running element count of the whole tree
740 * (to ensure the enum234 routines see them all).
741 */
742 ctx->elemcount += nelems;
743
744 /*
745 * Check ordering property: all elements should be strictly >
746 * lowbound, strictly < highbound, and strictly < each other in
747 * sequence. (lowbound and highbound are NULL at edges of tree
748 * - both NULL at root node - and NULL is considered to be <
749 * everything and > everything. IYSWIM.)
750 */
751 for (i = -1; i < nelems; i++) {
752 void *lower = (i == -1 ? lowbound : node->elems[i]);
753 void *higher = (i+1 == nelems ? highbound : node->elems[i+1]);
754 if (lower && higher && cmp(lower, higher) >= 0) {
755 error("node %p: kid comparison [%d=%s,%d=%s] failed",
756 node, i, lower, i+1, higher);
757 }
758 }
759
760 /*
761 * Check parent pointers: all non-NULL kids should have a
762 * parent pointer coming back to this node.
763 */
764 for (i = 0; i < nkids; i++)
765 if (node->kids[i]->parent != node) {
766 error("node %p kid %d: parent ptr is %p not %p",
767 node, i, node->kids[i]->parent, node);
768 }
769
770
771 /*
772 * Now (finally!) recurse into subtrees.
773 */
774 for (i = 0; i < nkids; i++) {
775 void *lower = (i == 0 ? lowbound : node->elems[i-1]);
776 void *higher = (i >= nelems ? highbound : node->elems[i]);
777 chknode(ctx, level+1, node->kids[i], lower, higher);
778 }
779}
780
781void verify(void) {
782 chkctx ctx;
783 enum234 e;
784 int i;
785 void *p;
786
787 ctx.treedepth = -1; /* depth unknown yet */
788 ctx.elemcount = 0; /* no elements seen yet */
789 /*
790 * Verify validity of tree properties.
791 */
792 if (tree->root)
793 chknode(&ctx, 0, tree->root, NULL, NULL);
794 printf("tree depth: %d\n", ctx.treedepth);
795 /*
796 * Enumerate the tree and ensure it matches up to the array.
797 */
798 for (i = 0, p = first234(tree, &e);
799 p;
800 i++, p = next234(&e)) {
801 if (i >= arraylen)
802 error("tree contains more than %d elements", arraylen);
803 if (array[i] != p)
804 error("enum at position %d: array says %s, tree says %s",
805 i, array[i], p);
806 }
807 if (i != ctx.elemcount) {
808 error("tree really contains %d elements, enum gave %d",
809 i, ctx.elemcount);
810 }
811 if (i < arraylen) {
812 error("enum gave only %d elements, array has %d", i, arraylen);
813 }
814}
815
816void addtest(void *elem) {
817 int i, j;
818 void *retval, *realret;
819
820 if (arraysize < arraylen+1) {
821 arraysize = arraylen+1+256;
822 array = (array == NULL ? malloc(arraysize*sizeof(*array)) :
823 realloc(array, arraysize*sizeof(*array)));
824 }
825
826 i = 0;
827 while (i < arraylen && cmp(elem, array[i]) > 0)
828 i++;
829 /* now i points to the first element >= elem */
830 if (i < arraylen && !cmp(elem, array[i]))
831 retval = array[i]; /* expect that returned not elem */
832 else {
833 retval = elem; /* expect elem returned (success) */
834 for (j = arraylen; j > i; j--)
835 array[j] = array[j-1];
836 array[i] = elem; /* add elem to array */
837 arraylen++;
838 }
839
840 realret = add234(tree, elem);
841 if (realret != retval) {
842 error("add: retval was %p expected %p", realret, retval);
843 }
844
845 verify();
846}
847
848void deltest(void *elem) {
849 int i;
850
851 i = 0;
852 while (i < arraylen && cmp(elem, array[i]) > 0)
853 i++;
854 /* now i points to the first element >= elem */
855 if (i >= arraylen || cmp(elem, array[i]) != 0)
856 return; /* don't do it! */
857 else {
858 while (i < arraylen-1) {
859 array[i] = array[i+1];
860 i++;
861 }
862 arraylen--; /* delete elem from array */
863 }
864
865 del234(tree, elem);
866
867 verify();
febd9a0f 868}
2d56b16f 869
870/* A sample data set and test utility. Designed for pseudo-randomness,
871 * and yet repeatability. */
872
873/*
874 * This random number generator uses the `portable implementation'
875 * given in ANSI C99 draft N869. It assumes `unsigned' is 32 bits;
876 * change it if not.
877 */
878int randomnumber(unsigned *seed) {
879 *seed *= 1103515245;
880 *seed += 12345;
881 return ((*seed) / 65536) % 32768;
febd9a0f 882}
883
2d56b16f 884int mycmp(void *av, void *bv) {
885 char const *a = (char const *)av;
886 char const *b = (char const *)bv;
febd9a0f 887 return strcmp(a, b);
888}
889
2d56b16f 890#define lenof(x) ( sizeof((x)) / sizeof(*(x)) )
891
892char *strings[] = {
893 "a", "ab", "absque", "coram", "de",
894 "palam", "clam", "cum", "ex", "e",
895 "sine", "tenus", "pro", "prae",
896 "banana", "carrot", "cabbage", "broccoli", "onion", "zebra",
897 "penguin", "blancmange", "pangolin", "whale", "hedgehog",
898 "giraffe", "peanut", "bungee", "foo", "bar", "baz", "quux",
899 "murfl", "spoo", "breen", "flarn", "octothorpe",
900 "snail", "tiger", "elephant", "octopus", "warthog", "armadillo",
901 "aardvark", "wyvern", "dragon", "elf", "dwarf", "orc", "goblin",
902 "pixie", "basilisk", "warg", "ape", "lizard", "newt", "shopkeeper",
903 "wand", "ring", "amulet"
904};
905
906#define NSTR lenof(strings)
907
febd9a0f 908int main(void) {
2d56b16f 909 int in[NSTR];
910 int i, j;
911 unsigned seed = 0;
912
913 for (i = 0; i < NSTR; i++) in[i] = 0;
914 array = NULL;
915 arraylen = arraysize = 0;
916 tree = newtree234(mycmp);
917 cmp = mycmp;
918
919 verify();
920 for (i = 0; i < 10000; i++) {
921 j = randomnumber(&seed);
922 j %= NSTR;
923 printf("trial: %d\n", i);
924 if (in[j]) {
925 printf("deleting %s (%d)\n", strings[j], j);
926 deltest(strings[j]);
927 in[j] = 0;
928 } else {
929 printf("adding %s (%d)\n", strings[j], j);
930 addtest(strings[j]);
931 in[j] = 1;
932 }
933 }
934
935 while (arraylen > 0) {
936 j = randomnumber(&seed);
937 j %= arraylen;
938 deltest(array[j]);
939 }
940
941 return 0;
febd9a0f 942}
2d56b16f 943
febd9a0f 944#endif