Add missing checks in update_for_intended_size() in the font selector
[sgt/putty] / tree234.c
CommitLineData
febd9a0f 1/*
d2371c81 2 * tree234.c: reasonably generic counted 2-3-4 tree routines.
3 *
4 * This file is copyright 1999-2001 Simon Tatham.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
febd9a0f 26 */
27
28#include <stdio.h>
29#include <stdlib.h>
d2371c81 30#include <assert.h>
dcbde236 31
3d88e64d 32#include "puttymem.h"
febd9a0f 33#include "tree234.h"
34
febd9a0f 35#ifdef TEST
36#define LOG(x) (printf x)
37#else
cdd6c586 38#define LOG(x)
febd9a0f 39#endif
40
d2371c81 41typedef struct node234_Tag node234;
42
febd9a0f 43struct tree234_Tag {
44 node234 *root;
45 cmpfn234 cmp;
46};
47
48struct node234_Tag {
49 node234 *parent;
50 node234 *kids[4];
d2371c81 51 int counts[4];
febd9a0f 52 void *elems[3];
53};
54
55/*
56 * Create a 2-3-4 tree.
57 */
32874aea 58tree234 *newtree234(cmpfn234 cmp)
59{
3d88e64d 60 tree234 *ret = snew(tree234);
febd9a0f 61 LOG(("created tree %p\n", ret));
62 ret->root = NULL;
63 ret->cmp = cmp;
64 return ret;
65}
66
67/*
68 * Free a 2-3-4 tree (not including freeing the elements).
69 */
32874aea 70static void freenode234(node234 * n)
71{
febd9a0f 72 if (!n)
73 return;
74 freenode234(n->kids[0]);
75 freenode234(n->kids[1]);
76 freenode234(n->kids[2]);
77 freenode234(n->kids[3]);
78 sfree(n);
79}
32874aea 80
81void freetree234(tree234 * t)
82{
febd9a0f 83 freenode234(t->root);
84 sfree(t);
85}
86
87/*
d2371c81 88 * Internal function to count a node.
89 */
32874aea 90static int countnode234(node234 * n)
91{
d2371c81 92 int count = 0;
93 int i;
c404e5b3 94 if (!n)
95 return 0;
d2371c81 96 for (i = 0; i < 4; i++)
97 count += n->counts[i];
98 for (i = 0; i < 3; i++)
99 if (n->elems[i])
100 count++;
101 return count;
102}
103
104/*
105 * Count the elements in a tree.
106 */
32874aea 107int count234(tree234 * t)
108{
d2371c81 109 if (t->root)
110 return countnode234(t->root);
111 else
112 return 0;
113}
114
115/*
febd9a0f 116 * Add an element e to a 2-3-4 tree t. Returns e on success, or if
117 * an existing element compares equal, returns that.
118 */
32874aea 119static void *add234_internal(tree234 * t, void *e, int index)
120{
febd9a0f 121 node234 *n, **np, *left, *right;
122 void *orig_e = e;
d2371c81 123 int c, lcount, rcount;
febd9a0f 124
125 LOG(("adding node %p to tree %p\n", e, t));
126 if (t->root == NULL) {
3d88e64d 127 t->root = snew(node234);
febd9a0f 128 t->root->elems[1] = t->root->elems[2] = NULL;
129 t->root->kids[0] = t->root->kids[1] = NULL;
130 t->root->kids[2] = t->root->kids[3] = NULL;
d2371c81 131 t->root->counts[0] = t->root->counts[1] = 0;
132 t->root->counts[2] = t->root->counts[3] = 0;
febd9a0f 133 t->root->parent = NULL;
134 t->root->elems[0] = e;
135 LOG((" created root %p\n", t->root));
136 return orig_e;
137 }
138
8a9977e5 139 n = NULL; /* placate gcc; will always be set below since t->root != NULL */
febd9a0f 140 np = &t->root;
141 while (*np) {
d2371c81 142 int childnum;
febd9a0f 143 n = *np;
d2371c81 144 LOG((" node %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d\n",
145 n,
146 n->kids[0], n->counts[0], n->elems[0],
147 n->kids[1], n->counts[1], n->elems[1],
148 n->kids[2], n->counts[2], n->elems[2],
149 n->kids[3], n->counts[3]));
150 if (index >= 0) {
151 if (!n->kids[0]) {
152 /*
153 * Leaf node. We want to insert at kid position
154 * equal to the index:
155 *
156 * 0 A 1 B 2 C 3
157 */
158 childnum = index;
159 } else {
160 /*
161 * Internal node. We always descend through it (add
162 * always starts at the bottom, never in the
163 * middle).
164 */
32874aea 165 do { /* this is a do ... while (0) to allow `break' */
d2371c81 166 if (index <= n->counts[0]) {
167 childnum = 0;
168 break;
169 }
170 index -= n->counts[0] + 1;
171 if (index <= n->counts[1]) {
172 childnum = 1;
173 break;
174 }
175 index -= n->counts[1] + 1;
176 if (index <= n->counts[2]) {
177 childnum = 2;
178 break;
179 }
180 index -= n->counts[2] + 1;
181 if (index <= n->counts[3]) {
182 childnum = 3;
183 break;
184 }
185 return NULL; /* error: index out of range */
186 } while (0);
187 }
188 } else {
189 if ((c = t->cmp(e, n->elems[0])) < 0)
190 childnum = 0;
191 else if (c == 0)
32874aea 192 return n->elems[0]; /* already exists */
193 else if (n->elems[1] == NULL
194 || (c = t->cmp(e, n->elems[1])) < 0) childnum = 1;
d2371c81 195 else if (c == 0)
32874aea 196 return n->elems[1]; /* already exists */
197 else if (n->elems[2] == NULL
198 || (c = t->cmp(e, n->elems[2])) < 0) childnum = 2;
d2371c81 199 else if (c == 0)
32874aea 200 return n->elems[2]; /* already exists */
d2371c81 201 else
202 childnum = 3;
203 }
204 np = &n->kids[childnum];
205 LOG((" moving to child %d (%p)\n", childnum, *np));
febd9a0f 206 }
207
208 /*
209 * We need to insert the new element in n at position np.
210 */
32874aea 211 left = NULL;
212 lcount = 0;
213 right = NULL;
214 rcount = 0;
febd9a0f 215 while (n) {
d2371c81 216 LOG((" at %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d\n",
217 n,
218 n->kids[0], n->counts[0], n->elems[0],
219 n->kids[1], n->counts[1], n->elems[1],
220 n->kids[2], n->counts[2], n->elems[2],
221 n->kids[3], n->counts[3]));
222 LOG((" need to insert %p/%d [%p] %p/%d at position %d\n",
223 left, lcount, e, right, rcount, np - n->kids));
febd9a0f 224 if (n->elems[1] == NULL) {
225 /*
226 * Insert in a 2-node; simple.
227 */
228 if (np == &n->kids[0]) {
229 LOG((" inserting on left of 2-node\n"));
32874aea 230 n->kids[2] = n->kids[1];
231 n->counts[2] = n->counts[1];
febd9a0f 232 n->elems[1] = n->elems[0];
32874aea 233 n->kids[1] = right;
234 n->counts[1] = rcount;
febd9a0f 235 n->elems[0] = e;
32874aea 236 n->kids[0] = left;
237 n->counts[0] = lcount;
238 } else { /* np == &n->kids[1] */
febd9a0f 239 LOG((" inserting on right of 2-node\n"));
32874aea 240 n->kids[2] = right;
241 n->counts[2] = rcount;
febd9a0f 242 n->elems[1] = e;
32874aea 243 n->kids[1] = left;
244 n->counts[1] = lcount;
febd9a0f 245 }
32874aea 246 if (n->kids[0])
247 n->kids[0]->parent = n;
248 if (n->kids[1])
249 n->kids[1]->parent = n;
250 if (n->kids[2])
251 n->kids[2]->parent = n;
febd9a0f 252 LOG((" done\n"));
253 break;
254 } else if (n->elems[2] == NULL) {
255 /*
256 * Insert in a 3-node; simple.
257 */
258 if (np == &n->kids[0]) {
259 LOG((" inserting on left of 3-node\n"));
32874aea 260 n->kids[3] = n->kids[2];
261 n->counts[3] = n->counts[2];
febd9a0f 262 n->elems[2] = n->elems[1];
32874aea 263 n->kids[2] = n->kids[1];
264 n->counts[2] = n->counts[1];
febd9a0f 265 n->elems[1] = n->elems[0];
32874aea 266 n->kids[1] = right;
267 n->counts[1] = rcount;
febd9a0f 268 n->elems[0] = e;
32874aea 269 n->kids[0] = left;
270 n->counts[0] = lcount;
febd9a0f 271 } else if (np == &n->kids[1]) {
272 LOG((" inserting in middle of 3-node\n"));
32874aea 273 n->kids[3] = n->kids[2];
274 n->counts[3] = n->counts[2];
febd9a0f 275 n->elems[2] = n->elems[1];
32874aea 276 n->kids[2] = right;
277 n->counts[2] = rcount;
febd9a0f 278 n->elems[1] = e;
32874aea 279 n->kids[1] = left;
280 n->counts[1] = lcount;
281 } else { /* np == &n->kids[2] */
febd9a0f 282 LOG((" inserting on right of 3-node\n"));
32874aea 283 n->kids[3] = right;
284 n->counts[3] = rcount;
febd9a0f 285 n->elems[2] = e;
32874aea 286 n->kids[2] = left;
287 n->counts[2] = lcount;
febd9a0f 288 }
32874aea 289 if (n->kids[0])
290 n->kids[0]->parent = n;
291 if (n->kids[1])
292 n->kids[1]->parent = n;
293 if (n->kids[2])
294 n->kids[2]->parent = n;
295 if (n->kids[3])
296 n->kids[3]->parent = n;
febd9a0f 297 LOG((" done\n"));
298 break;
299 } else {
3d88e64d 300 node234 *m = snew(node234);
febd9a0f 301 m->parent = n->parent;
302 LOG((" splitting a 4-node; created new node %p\n", m));
303 /*
304 * Insert in a 4-node; split into a 2-node and a
305 * 3-node, and move focus up a level.
306 *
307 * I don't think it matters which way round we put the
308 * 2 and the 3. For simplicity, we'll put the 3 first
309 * always.
310 */
311 if (np == &n->kids[0]) {
32874aea 312 m->kids[0] = left;
313 m->counts[0] = lcount;
febd9a0f 314 m->elems[0] = e;
32874aea 315 m->kids[1] = right;
316 m->counts[1] = rcount;
febd9a0f 317 m->elems[1] = n->elems[0];
32874aea 318 m->kids[2] = n->kids[1];
319 m->counts[2] = n->counts[1];
febd9a0f 320 e = n->elems[1];
32874aea 321 n->kids[0] = n->kids[2];
322 n->counts[0] = n->counts[2];
febd9a0f 323 n->elems[0] = n->elems[2];
32874aea 324 n->kids[1] = n->kids[3];
325 n->counts[1] = n->counts[3];
febd9a0f 326 } else if (np == &n->kids[1]) {
32874aea 327 m->kids[0] = n->kids[0];
328 m->counts[0] = n->counts[0];
febd9a0f 329 m->elems[0] = n->elems[0];
32874aea 330 m->kids[1] = left;
331 m->counts[1] = lcount;
febd9a0f 332 m->elems[1] = e;
32874aea 333 m->kids[2] = right;
334 m->counts[2] = rcount;
febd9a0f 335 e = n->elems[1];
32874aea 336 n->kids[0] = n->kids[2];
337 n->counts[0] = n->counts[2];
febd9a0f 338 n->elems[0] = n->elems[2];
32874aea 339 n->kids[1] = n->kids[3];
340 n->counts[1] = n->counts[3];
febd9a0f 341 } else if (np == &n->kids[2]) {
32874aea 342 m->kids[0] = n->kids[0];
343 m->counts[0] = n->counts[0];
febd9a0f 344 m->elems[0] = n->elems[0];
32874aea 345 m->kids[1] = n->kids[1];
346 m->counts[1] = n->counts[1];
febd9a0f 347 m->elems[1] = n->elems[1];
32874aea 348 m->kids[2] = left;
349 m->counts[2] = lcount;
febd9a0f 350 /* e = e; */
32874aea 351 n->kids[0] = right;
352 n->counts[0] = rcount;
febd9a0f 353 n->elems[0] = n->elems[2];
32874aea 354 n->kids[1] = n->kids[3];
355 n->counts[1] = n->counts[3];
356 } else { /* np == &n->kids[3] */
357 m->kids[0] = n->kids[0];
358 m->counts[0] = n->counts[0];
febd9a0f 359 m->elems[0] = n->elems[0];
32874aea 360 m->kids[1] = n->kids[1];
361 m->counts[1] = n->counts[1];
febd9a0f 362 m->elems[1] = n->elems[1];
32874aea 363 m->kids[2] = n->kids[2];
364 m->counts[2] = n->counts[2];
365 n->kids[0] = left;
366 n->counts[0] = lcount;
febd9a0f 367 n->elems[0] = e;
32874aea 368 n->kids[1] = right;
369 n->counts[1] = rcount;
febd9a0f 370 e = n->elems[2];
371 }
372 m->kids[3] = n->kids[3] = n->kids[2] = NULL;
d2371c81 373 m->counts[3] = n->counts[3] = n->counts[2] = 0;
febd9a0f 374 m->elems[2] = n->elems[2] = n->elems[1] = NULL;
32874aea 375 if (m->kids[0])
376 m->kids[0]->parent = m;
377 if (m->kids[1])
378 m->kids[1]->parent = m;
379 if (m->kids[2])
380 m->kids[2]->parent = m;
381 if (n->kids[0])
382 n->kids[0]->parent = n;
383 if (n->kids[1])
384 n->kids[1]->parent = n;
d2371c81 385 LOG((" left (%p): %p/%d [%p] %p/%d [%p] %p/%d\n", m,
386 m->kids[0], m->counts[0], m->elems[0],
387 m->kids[1], m->counts[1], m->elems[1],
388 m->kids[2], m->counts[2]));
389 LOG((" right (%p): %p/%d [%p] %p/%d\n", n,
390 n->kids[0], n->counts[0], n->elems[0],
391 n->kids[1], n->counts[1]));
32874aea 392 left = m;
393 lcount = countnode234(left);
394 right = n;
395 rcount = countnode234(right);
febd9a0f 396 }
397 if (n->parent)
398 np = (n->parent->kids[0] == n ? &n->parent->kids[0] :
399 n->parent->kids[1] == n ? &n->parent->kids[1] :
400 n->parent->kids[2] == n ? &n->parent->kids[2] :
401 &n->parent->kids[3]);
402 n = n->parent;
403 }
404
405 /*
406 * If we've come out of here by `break', n will still be
d2371c81 407 * non-NULL and all we need to do is go back up the tree
408 * updating counts. If we've come here because n is NULL, we
409 * need to create a new root for the tree because the old one
410 * has just split into two. */
411 if (n) {
412 while (n->parent) {
413 int count = countnode234(n);
414 int childnum;
415 childnum = (n->parent->kids[0] == n ? 0 :
416 n->parent->kids[1] == n ? 1 :
417 n->parent->kids[2] == n ? 2 : 3);
418 n->parent->counts[childnum] = count;
419 n = n->parent;
420 }
421 } else {
febd9a0f 422 LOG((" root is overloaded, split into two\n"));
3d88e64d 423 t->root = snew(node234);
32874aea 424 t->root->kids[0] = left;
425 t->root->counts[0] = lcount;
febd9a0f 426 t->root->elems[0] = e;
32874aea 427 t->root->kids[1] = right;
428 t->root->counts[1] = rcount;
febd9a0f 429 t->root->elems[1] = NULL;
32874aea 430 t->root->kids[2] = NULL;
431 t->root->counts[2] = 0;
febd9a0f 432 t->root->elems[2] = NULL;
32874aea 433 t->root->kids[3] = NULL;
434 t->root->counts[3] = 0;
febd9a0f 435 t->root->parent = NULL;
32874aea 436 if (t->root->kids[0])
437 t->root->kids[0]->parent = t->root;
438 if (t->root->kids[1])
439 t->root->kids[1]->parent = t->root;
d2371c81 440 LOG((" new root is %p/%d [%p] %p/%d\n",
441 t->root->kids[0], t->root->counts[0],
32874aea 442 t->root->elems[0], t->root->kids[1], t->root->counts[1]));
febd9a0f 443 }
444
445 return orig_e;
446}
447
32874aea 448void *add234(tree234 * t, void *e)
449{
d2371c81 450 if (!t->cmp) /* tree is unsorted */
451 return NULL;
452
453 return add234_internal(t, e, -1);
454}
32874aea 455void *addpos234(tree234 * t, void *e, int index)
456{
d2371c81 457 if (index < 0 || /* index out of range */
458 t->cmp) /* tree is sorted */
459 return NULL; /* return failure */
460
32874aea 461 return add234_internal(t, e, index); /* this checks the upper bound */
d2371c81 462}
463
febd9a0f 464/*
d2371c81 465 * Look up the element at a given numeric index in a 2-3-4 tree.
466 * Returns NULL if the index is out of range.
febd9a0f 467 */
32874aea 468void *index234(tree234 * t, int index)
469{
febd9a0f 470 node234 *n;
febd9a0f 471
d2371c81 472 if (!t->root)
473 return NULL; /* tree is empty */
febd9a0f 474
d2371c81 475 if (index < 0 || index >= countnode234(t->root))
476 return NULL; /* out of range */
febd9a0f 477
478 n = t->root;
32874aea 479
febd9a0f 480 while (n) {
d2371c81 481 if (index < n->counts[0])
febd9a0f 482 n = n->kids[0];
d2371c81 483 else if (index -= n->counts[0] + 1, index < 0)
febd9a0f 484 return n->elems[0];
d2371c81 485 else if (index < n->counts[1])
febd9a0f 486 n = n->kids[1];
d2371c81 487 else if (index -= n->counts[1] + 1, index < 0)
febd9a0f 488 return n->elems[1];
d2371c81 489 else if (index < n->counts[2])
febd9a0f 490 n = n->kids[2];
d2371c81 491 else if (index -= n->counts[2] + 1, index < 0)
febd9a0f 492 return n->elems[2];
493 else
494 n = n->kids[3];
495 }
496
d2371c81 497 /* We shouldn't ever get here. I wonder how we did. */
498 return NULL;
499}
500
501/*
502 * Find an element e in a sorted 2-3-4 tree t. Returns NULL if not
503 * found. e is always passed as the first argument to cmp, so cmp
504 * can be an asymmetric function if desired. cmp can also be passed
505 * as NULL, in which case the compare function from the tree proper
506 * will be used.
507 */
32874aea 508void *findrelpos234(tree234 * t, void *e, cmpfn234 cmp,
509 int relation, int *index)
510{
d2371c81 511 node234 *n;
512 void *ret;
513 int c;
514 int idx, ecount, kcount, cmpret;
515
516 if (t->root == NULL)
517 return NULL;
518
519 if (cmp == NULL)
520 cmp = t->cmp;
521
522 n = t->root;
febd9a0f 523 /*
d2371c81 524 * Attempt to find the element itself.
febd9a0f 525 */
d2371c81 526 idx = 0;
527 ecount = -1;
528 /*
529 * Prepare a fake `cmp' result if e is NULL.
530 */
531 cmpret = 0;
532 if (e == NULL) {
533 assert(relation == REL234_LT || relation == REL234_GT);
534 if (relation == REL234_LT)
535 cmpret = +1; /* e is a max: always greater */
536 else if (relation == REL234_GT)
537 cmpret = -1; /* e is a min: always smaller */
538 }
539 while (1) {
540 for (kcount = 0; kcount < 4; kcount++) {
541 if (kcount >= 3 || n->elems[kcount] == NULL ||
542 (c = cmpret ? cmpret : cmp(e, n->elems[kcount])) < 0) {
543 break;
544 }
32874aea 545 if (n->kids[kcount])
546 idx += n->counts[kcount];
d2371c81 547 if (c == 0) {
548 ecount = kcount;
549 break;
550 }
551 idx++;
552 }
553 if (ecount >= 0)
554 break;
555 if (n->kids[kcount])
556 n = n->kids[kcount];
557 else
558 break;
559 }
560
561 if (ecount >= 0) {
562 /*
563 * We have found the element we're looking for. It's
564 * n->elems[ecount], at tree index idx. If our search
565 * relation is EQ, LE or GE we can now go home.
566 */
567 if (relation != REL234_LT && relation != REL234_GT) {
32874aea 568 if (index)
569 *index = idx;
d2371c81 570 return n->elems[ecount];
571 }
572
573 /*
574 * Otherwise, we'll do an indexed lookup for the previous
575 * or next element. (It would be perfectly possible to
576 * implement these search types in a non-counted tree by
577 * going back up from where we are, but far more fiddly.)
578 */
579 if (relation == REL234_LT)
580 idx--;
581 else
582 idx++;
583 } else {
584 /*
585 * We've found our way to the bottom of the tree and we
586 * know where we would insert this node if we wanted to:
587 * we'd put it in in place of the (empty) subtree
588 * n->kids[kcount], and it would have index idx
589 *
590 * But the actual element isn't there. So if our search
591 * relation is EQ, we're doomed.
592 */
593 if (relation == REL234_EQ)
594 return NULL;
595
596 /*
597 * Otherwise, we must do an index lookup for index idx-1
598 * (if we're going left - LE or LT) or index idx (if we're
599 * going right - GE or GT).
600 */
601 if (relation == REL234_LT || relation == REL234_LE) {
602 idx--;
603 }
604 }
605
606 /*
607 * We know the index of the element we want; just call index234
608 * to do the rest. This will return NULL if the index is out of
609 * bounds, which is exactly what we want.
610 */
611 ret = index234(t, idx);
32874aea 612 if (ret && index)
613 *index = idx;
d2371c81 614 return ret;
615}
32874aea 616void *find234(tree234 * t, void *e, cmpfn234 cmp)
617{
d2371c81 618 return findrelpos234(t, e, cmp, REL234_EQ, NULL);
619}
32874aea 620void *findrel234(tree234 * t, void *e, cmpfn234 cmp, int relation)
621{
d2371c81 622 return findrelpos234(t, e, cmp, relation, NULL);
623}
32874aea 624void *findpos234(tree234 * t, void *e, cmpfn234 cmp, int *index)
625{
d2371c81 626 return findrelpos234(t, e, cmp, REL234_EQ, index);
febd9a0f 627}
628
629/*
630 * Delete an element e in a 2-3-4 tree. Does not free the element,
631 * merely removes all links to it from the tree nodes.
632 */
32874aea 633static void *delpos234_internal(tree234 * t, int index)
634{
febd9a0f 635 node234 *n;
d2371c81 636 void *retval;
febd9a0f 637 int ei = -1;
638
d2371c81 639 retval = 0;
640
febd9a0f 641 n = t->root;
d2371c81 642 LOG(("deleting item %d from tree %p\n", index, t));
febd9a0f 643 while (1) {
644 while (n) {
febd9a0f 645 int ki;
646 node234 *sub;
647
32874aea 648 LOG(
649 (" node %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d index=%d\n",
650 n, n->kids[0], n->counts[0], n->elems[0], n->kids[1],
651 n->counts[1], n->elems[1], n->kids[2], n->counts[2],
652 n->elems[2], n->kids[3], n->counts[3], index));
d2371c81 653 if (index < n->counts[0]) {
febd9a0f 654 ki = 0;
32874aea 655 } else if (index -= n->counts[0] + 1, index < 0) {
656 ei = 0;
657 break;
d2371c81 658 } else if (index < n->counts[1]) {
febd9a0f 659 ki = 1;
32874aea 660 } else if (index -= n->counts[1] + 1, index < 0) {
661 ei = 1;
662 break;
d2371c81 663 } else if (index < n->counts[2]) {
febd9a0f 664 ki = 2;
32874aea 665 } else if (index -= n->counts[2] + 1, index < 0) {
666 ei = 2;
667 break;
febd9a0f 668 } else {
669 ki = 3;
670 }
671 /*
672 * Recurse down to subtree ki. If it has only one element,
673 * we have to do some transformation to start with.
674 */
675 LOG((" moving to subtree %d\n", ki));
676 sub = n->kids[ki];
677 if (!sub->elems[1]) {
678 LOG((" subtree has only one element!\n", ki));
32874aea 679 if (ki > 0 && n->kids[ki - 1]->elems[1]) {
febd9a0f 680 /*
681 * Case 3a, left-handed variant. Child ki has
682 * only one element, but child ki-1 has two or
683 * more. So we need to move a subtree from ki-1
684 * to ki.
685 *
686 * . C . . B .
687 * / \ -> / \
688 * [more] a A b B c d D e [more] a A b c C d D e
689 */
32874aea 690 node234 *sib = n->kids[ki - 1];
febd9a0f 691 int lastelem = (sib->elems[2] ? 2 :
692 sib->elems[1] ? 1 : 0);
693 sub->kids[2] = sub->kids[1];
d2371c81 694 sub->counts[2] = sub->counts[1];
febd9a0f 695 sub->elems[1] = sub->elems[0];
696 sub->kids[1] = sub->kids[0];
d2371c81 697 sub->counts[1] = sub->counts[0];
32874aea 698 sub->elems[0] = n->elems[ki - 1];
699 sub->kids[0] = sib->kids[lastelem + 1];
700 sub->counts[0] = sib->counts[lastelem + 1];
701 if (sub->kids[0])
702 sub->kids[0]->parent = sub;
703 n->elems[ki - 1] = sib->elems[lastelem];
704 sib->kids[lastelem + 1] = NULL;
705 sib->counts[lastelem + 1] = 0;
febd9a0f 706 sib->elems[lastelem] = NULL;
d2371c81 707 n->counts[ki] = countnode234(sub);
febd9a0f 708 LOG((" case 3a left\n"));
32874aea 709 LOG(
710 (" index and left subtree count before adjustment: %d, %d\n",
711 index, n->counts[ki - 1]));
712 index += n->counts[ki - 1];
713 n->counts[ki - 1] = countnode234(sib);
714 index -= n->counts[ki - 1];
715 LOG(
716 (" index and left subtree count after adjustment: %d, %d\n",
717 index, n->counts[ki - 1]));
718 } else if (ki < 3 && n->kids[ki + 1]
719 && n->kids[ki + 1]->elems[1]) {
febd9a0f 720 /*
721 * Case 3a, right-handed variant. ki has only
722 * one element but ki+1 has two or more. Move a
723 * subtree from ki+1 to ki.
724 *
725 * . B . . C .
726 * / \ -> / \
727 * a A b c C d D e [more] a A b B c d D e [more]
728 */
32874aea 729 node234 *sib = n->kids[ki + 1];
febd9a0f 730 int j;
731 sub->elems[1] = n->elems[ki];
732 sub->kids[2] = sib->kids[0];
d2371c81 733 sub->counts[2] = sib->counts[0];
32874aea 734 if (sub->kids[2])
735 sub->kids[2]->parent = sub;
febd9a0f 736 n->elems[ki] = sib->elems[0];
737 sib->kids[0] = sib->kids[1];
d2371c81 738 sib->counts[0] = sib->counts[1];
32874aea 739 for (j = 0; j < 2 && sib->elems[j + 1]; j++) {
740 sib->kids[j + 1] = sib->kids[j + 2];
741 sib->counts[j + 1] = sib->counts[j + 2];
742 sib->elems[j] = sib->elems[j + 1];
febd9a0f 743 }
32874aea 744 sib->kids[j + 1] = NULL;
745 sib->counts[j + 1] = 0;
febd9a0f 746 sib->elems[j] = NULL;
d2371c81 747 n->counts[ki] = countnode234(sub);
32874aea 748 n->counts[ki + 1] = countnode234(sib);
febd9a0f 749 LOG((" case 3a right\n"));
750 } else {
751 /*
752 * Case 3b. ki has only one element, and has no
753 * neighbour with more than one. So pick a
754 * neighbour and merge it with ki, taking an
755 * element down from n to go in the middle.
756 *
757 * . B . .
758 * / \ -> |
759 * a A b c C d a A b B c C d
760 *
761 * (Since at all points we have avoided
762 * descending to a node with only one element,
763 * we can be sure that n is not reduced to
764 * nothingness by this move, _unless_ it was
765 * the very first node, ie the root of the
766 * tree. In that case we remove the now-empty
767 * root and replace it with its single large
768 * child as shown.)
769 */
770 node234 *sib;
771 int j;
772
d2371c81 773 if (ki > 0) {
febd9a0f 774 ki--;
d2371c81 775 index += n->counts[ki] + 1;
776 }
febd9a0f 777 sib = n->kids[ki];
32874aea 778 sub = n->kids[ki + 1];
febd9a0f 779
780 sub->kids[3] = sub->kids[1];
d2371c81 781 sub->counts[3] = sub->counts[1];
febd9a0f 782 sub->elems[2] = sub->elems[0];
783 sub->kids[2] = sub->kids[0];
d2371c81 784 sub->counts[2] = sub->counts[0];
febd9a0f 785 sub->elems[1] = n->elems[ki];
786 sub->kids[1] = sib->kids[1];
d2371c81 787 sub->counts[1] = sib->counts[1];
32874aea 788 if (sub->kids[1])
789 sub->kids[1]->parent = sub;
febd9a0f 790 sub->elems[0] = sib->elems[0];
791 sub->kids[0] = sib->kids[0];
d2371c81 792 sub->counts[0] = sib->counts[0];
32874aea 793 if (sub->kids[0])
794 sub->kids[0]->parent = sub;
febd9a0f 795
32874aea 796 n->counts[ki + 1] = countnode234(sub);
d2371c81 797
febd9a0f 798 sfree(sib);
799
800 /*
801 * That's built the big node in sub. Now we
802 * need to remove the reference to sib in n.
803 */
32874aea 804 for (j = ki; j < 3 && n->kids[j + 1]; j++) {
805 n->kids[j] = n->kids[j + 1];
806 n->counts[j] = n->counts[j + 1];
807 n->elems[j] = j < 2 ? n->elems[j + 1] : NULL;
febd9a0f 808 }
809 n->kids[j] = NULL;
d2371c81 810 n->counts[j] = 0;
32874aea 811 if (j < 3)
812 n->elems[j] = NULL;
2d56b16f 813 LOG((" case 3b ki=%d\n", ki));
febd9a0f 814
815 if (!n->elems[0]) {
816 /*
817 * The root is empty and needs to be
818 * removed.
819 */
820 LOG((" shifting root!\n"));
821 t->root = sub;
822 sub->parent = NULL;
823 sfree(n);
824 }
825 }
826 }
827 n = sub;
828 }
d2371c81 829 if (!retval)
830 retval = n->elems[ei];
831
32874aea 832 if (ei == -1)
d2371c81 833 return NULL; /* although this shouldn't happen */
febd9a0f 834
835 /*
836 * Treat special case: this is the one remaining item in
837 * the tree. n is the tree root (no parent), has one
838 * element (no elems[1]), and has no kids (no kids[0]).
839 */
840 if (!n->parent && !n->elems[1] && !n->kids[0]) {
841 LOG((" removed last element in tree\n"));
842 sfree(n);
843 t->root = NULL;
d2371c81 844 return retval;
febd9a0f 845 }
846
847 /*
848 * Now we have the element we want, as n->elems[ei], and we
849 * have also arranged for that element not to be the only
850 * one in its node. So...
851 */
852
853 if (!n->kids[0] && n->elems[1]) {
854 /*
855 * Case 1. n is a leaf node with more than one element,
856 * so it's _really easy_. Just delete the thing and
857 * we're done.
858 */
859 int i;
860 LOG((" case 1\n"));
32874aea 861 for (i = ei; i < 2 && n->elems[i + 1]; i++)
862 n->elems[i] = n->elems[i + 1];
febd9a0f 863 n->elems[i] = NULL;
d2371c81 864 /*
865 * Having done that to the leaf node, we now go back up
866 * the tree fixing the counts.
867 */
868 while (n->parent) {
869 int childnum;
870 childnum = (n->parent->kids[0] == n ? 0 :
871 n->parent->kids[1] == n ? 1 :
872 n->parent->kids[2] == n ? 2 : 3);
873 n->parent->counts[childnum]--;
874 n = n->parent;
875 }
876 return retval; /* finished! */
febd9a0f 877 } else if (n->kids[ei]->elems[1]) {
878 /*
879 * Case 2a. n is an internal node, and the root of the
880 * subtree to the left of e has more than one element.
881 * So find the predecessor p to e (ie the largest node
882 * in that subtree), place it where e currently is, and
883 * then start the deletion process over again on the
884 * subtree with p as target.
885 */
886 node234 *m = n->kids[ei];
887 void *target;
888 LOG((" case 2a\n"));
889 while (m->kids[0]) {
890 m = (m->kids[3] ? m->kids[3] :
891 m->kids[2] ? m->kids[2] :
32874aea 892 m->kids[1] ? m->kids[1] : m->kids[0]);
febd9a0f 893 }
894 target = (m->elems[2] ? m->elems[2] :
895 m->elems[1] ? m->elems[1] : m->elems[0]);
896 n->elems[ei] = target;
32874aea 897 index = n->counts[ei] - 1;
febd9a0f 898 n = n->kids[ei];
32874aea 899 } else if (n->kids[ei + 1]->elems[1]) {
febd9a0f 900 /*
901 * Case 2b, symmetric to 2a but s/left/right/ and
902 * s/predecessor/successor/. (And s/largest/smallest/).
903 */
32874aea 904 node234 *m = n->kids[ei + 1];
febd9a0f 905 void *target;
906 LOG((" case 2b\n"));
907 while (m->kids[0]) {
908 m = m->kids[0];
909 }
910 target = m->elems[0];
911 n->elems[ei] = target;
32874aea 912 n = n->kids[ei + 1];
d2371c81 913 index = 0;
febd9a0f 914 } else {
915 /*
916 * Case 2c. n is an internal node, and the subtrees to
917 * the left and right of e both have only one element.
918 * So combine the two subnodes into a single big node
919 * with their own elements on the left and right and e
920 * in the middle, then restart the deletion process on
921 * that subtree, with e still as target.
922 */
32874aea 923 node234 *a = n->kids[ei], *b = n->kids[ei + 1];
febd9a0f 924 int j;
925
926 LOG((" case 2c\n"));
927 a->elems[1] = n->elems[ei];
928 a->kids[2] = b->kids[0];
d2371c81 929 a->counts[2] = b->counts[0];
32874aea 930 if (a->kids[2])
931 a->kids[2]->parent = a;
febd9a0f 932 a->elems[2] = b->elems[0];
933 a->kids[3] = b->kids[1];
d2371c81 934 a->counts[3] = b->counts[1];
32874aea 935 if (a->kids[3])
936 a->kids[3]->parent = a;
febd9a0f 937 sfree(b);
d2371c81 938 n->counts[ei] = countnode234(a);
febd9a0f 939 /*
940 * That's built the big node in a, and destroyed b. Now
941 * remove the reference to b (and e) in n.
942 */
32874aea 943 for (j = ei; j < 2 && n->elems[j + 1]; j++) {
944 n->elems[j] = n->elems[j + 1];
945 n->kids[j + 1] = n->kids[j + 2];
946 n->counts[j + 1] = n->counts[j + 2];
febd9a0f 947 }
948 n->elems[j] = NULL;
32874aea 949 n->kids[j + 1] = NULL;
950 n->counts[j + 1] = 0;
951 /*
952 * It's possible, in this case, that we've just removed
953 * the only element in the root of the tree. If so,
954 * shift the root.
955 */
956 if (n->elems[0] == NULL) {
957 LOG((" shifting root!\n"));
958 t->root = a;
959 a->parent = NULL;
960 sfree(n);
961 }
febd9a0f 962 /*
963 * Now go round the deletion process again, with n
964 * pointing at the new big node and e still the same.
965 */
966 n = a;
d2371c81 967 index = a->counts[0] + a->counts[1] + 1;
febd9a0f 968 }
969 }
970}
32874aea 971void *delpos234(tree234 * t, int index)
972{
d2371c81 973 if (index < 0 || index >= countnode234(t->root))
febd9a0f 974 return NULL;
d2371c81 975 return delpos234_internal(t, index);
febd9a0f 976}
32874aea 977void *del234(tree234 * t, void *e)
978{
d2371c81 979 int index;
980 if (!findrelpos234(t, e, NULL, REL234_EQ, &index))
981 return NULL; /* it wasn't in there anyway */
32874aea 982 return delpos234_internal(t, index); /* it's there; delete it. */
febd9a0f 983}
984
985#ifdef TEST
986
2d56b16f 987/*
988 * Test code for the 2-3-4 tree. This code maintains an alternative
989 * representation of the data in the tree, in an array (using the
990 * obvious and slow insert and delete functions). After each tree
7aa7c43a 991 * operation, the verify() function is called, which ensures all
d2371c81 992 * the tree properties are preserved:
993 * - node->child->parent always equals node
994 * - tree->root->parent always equals NULL
995 * - number of kids == 0 or number of elements + 1;
996 * - tree has the same depth everywhere
997 * - every node has at least one element
998 * - subtree element counts are accurate
999 * - any NULL kid pointer is accompanied by a zero count
1000 * - in a sorted tree: ordering property between elements of a
1001 * node and elements of its children is preserved
1002 * and also ensures the list represented by the tree is the same
1003 * list it should be. (This last check also doubly verifies the
1004 * ordering properties, because the `same list it should be' is by
1005 * definition correctly ordered. It also ensures all nodes are
1006 * distinct, because the enum functions would get caught in a loop
1007 * if not.)
2d56b16f 1008 */
1009
1010#include <stdarg.h>
1011
1012/*
1013 * Error reporting function.
1014 */
32874aea 1015void error(char *fmt, ...)
1016{
2d56b16f 1017 va_list ap;
1018 printf("ERROR: ");
1019 va_start(ap, fmt);
1020 vfprintf(stdout, fmt, ap);
1021 va_end(ap);
1022 printf("\n");
1023}
1024
1025/* The array representation of the data. */
1026void **array;
1027int arraylen, arraysize;
1028cmpfn234 cmp;
1029
1030/* The tree representation of the same data. */
1031tree234 *tree;
1032
1033typedef struct {
1034 int treedepth;
1035 int elemcount;
1036} chkctx;
1037
32874aea 1038int chknode(chkctx * ctx, int level, node234 * node,
1039 void *lowbound, void *highbound)
1040{
2d56b16f 1041 int nkids, nelems;
1042 int i;
d2371c81 1043 int count;
2d56b16f 1044
1045 /* Count the non-NULL kids. */
1046 for (nkids = 0; nkids < 4 && node->kids[nkids]; nkids++);
1047 /* Ensure no kids beyond the first NULL are non-NULL. */
1048 for (i = nkids; i < 4; i++)
32874aea 1049 if (node->kids[i]) {
1050 error("node %p: nkids=%d but kids[%d] non-NULL",
1051 node, nkids, i);
1052 } else if (node->counts[i]) {
1053 error("node %p: kids[%d] NULL but count[%d]=%d nonzero",
1054 node, i, i, node->counts[i]);
d2371c81 1055 }
2d56b16f 1056
1057 /* Count the non-NULL elements. */
1058 for (nelems = 0; nelems < 3 && node->elems[nelems]; nelems++);
1059 /* Ensure no elements beyond the first NULL are non-NULL. */
1060 for (i = nelems; i < 3; i++)
32874aea 1061 if (node->elems[i]) {
1062 error("node %p: nelems=%d but elems[%d] non-NULL",
1063 node, nelems, i);
1064 }
2d56b16f 1065
1066 if (nkids == 0) {
32874aea 1067 /*
1068 * If nkids==0, this is a leaf node; verify that the tree
1069 * depth is the same everywhere.
1070 */
1071 if (ctx->treedepth < 0)
1072 ctx->treedepth = level; /* we didn't know the depth yet */
1073 else if (ctx->treedepth != level)
1074 error("node %p: leaf at depth %d, previously seen depth %d",
1075 node, level, ctx->treedepth);
2d56b16f 1076 } else {
32874aea 1077 /*
1078 * If nkids != 0, then it should be nelems+1, unless nelems
1079 * is 0 in which case nkids should also be 0 (and so we
1080 * shouldn't be in this condition at all).
1081 */
1082 int shouldkids = (nelems ? nelems + 1 : 0);
1083 if (nkids != shouldkids) {
1084 error("node %p: %d elems should mean %d kids but has %d",
1085 node, nelems, shouldkids, nkids);
1086 }
2d56b16f 1087 }
1088
1089 /*
1090 * nelems should be at least 1.
1091 */
1092 if (nelems == 0) {
32874aea 1093 error("node %p: no elems", node, nkids);
2d56b16f 1094 }
1095
1096 /*
d2371c81 1097 * Add nelems to the running element count of the whole tree.
2d56b16f 1098 */
1099 ctx->elemcount += nelems;
1100
1101 /*
1102 * Check ordering property: all elements should be strictly >
1103 * lowbound, strictly < highbound, and strictly < each other in
1104 * sequence. (lowbound and highbound are NULL at edges of tree
1105 * - both NULL at root node - and NULL is considered to be <
1106 * everything and > everything. IYSWIM.)
1107 */
d2371c81 1108 if (cmp) {
1109 for (i = -1; i < nelems; i++) {
1110 void *lower = (i == -1 ? lowbound : node->elems[i]);
32874aea 1111 void *higher =
1112 (i + 1 == nelems ? highbound : node->elems[i + 1]);
d2371c81 1113 if (lower && higher && cmp(lower, higher) >= 0) {
1114 error("node %p: kid comparison [%d=%s,%d=%s] failed",
32874aea 1115 node, i, lower, i + 1, higher);
d2371c81 1116 }
1117 }
2d56b16f 1118 }
1119
1120 /*
1121 * Check parent pointers: all non-NULL kids should have a
1122 * parent pointer coming back to this node.
1123 */
1124 for (i = 0; i < nkids; i++)
32874aea 1125 if (node->kids[i]->parent != node) {
1126 error("node %p kid %d: parent ptr is %p not %p",
1127 node, i, node->kids[i]->parent, node);
1128 }
2d56b16f 1129
1130
1131 /*
1132 * Now (finally!) recurse into subtrees.
1133 */
d2371c81 1134 count = nelems;
1135
2d56b16f 1136 for (i = 0; i < nkids; i++) {
32874aea 1137 void *lower = (i == 0 ? lowbound : node->elems[i - 1]);
1138 void *higher = (i >= nelems ? highbound : node->elems[i]);
1139 int subcount =
1140 chknode(ctx, level + 1, node->kids[i], lower, higher);
d2371c81 1141 if (node->counts[i] != subcount) {
1142 error("node %p kid %d: count says %d, subtree really has %d",
1143 node, i, node->counts[i], subcount);
1144 }
32874aea 1145 count += subcount;
2d56b16f 1146 }
d2371c81 1147
1148 return count;
2d56b16f 1149}
1150
32874aea 1151void verify(void)
1152{
2d56b16f 1153 chkctx ctx;
2d56b16f 1154 int i;
1155 void *p;
1156
32874aea 1157 ctx.treedepth = -1; /* depth unknown yet */
1158 ctx.elemcount = 0; /* no elements seen yet */
2d56b16f 1159 /*
1160 * Verify validity of tree properties.
1161 */
d2371c81 1162 if (tree->root) {
1163 if (tree->root->parent != NULL)
1164 error("root->parent is %p should be null", tree->root->parent);
32874aea 1165 chknode(&ctx, 0, tree->root, NULL, NULL);
d2371c81 1166 }
2d56b16f 1167 printf("tree depth: %d\n", ctx.treedepth);
1168 /*
1169 * Enumerate the tree and ensure it matches up to the array.
1170 */
d2371c81 1171 for (i = 0; NULL != (p = index234(tree, i)); i++) {
32874aea 1172 if (i >= arraylen)
1173 error("tree contains more than %d elements", arraylen);
1174 if (array[i] != p)
1175 error("enum at position %d: array says %s, tree says %s",
1176 i, array[i], p);
2d56b16f 1177 }
d2371c81 1178 if (ctx.elemcount != i) {
32874aea 1179 error("tree really contains %d elements, enum gave %d",
1180 ctx.elemcount, i);
2d56b16f 1181 }
1182 if (i < arraylen) {
32874aea 1183 error("enum gave only %d elements, array has %d", i, arraylen);
2d56b16f 1184 }
d2371c81 1185 i = count234(tree);
1186 if (ctx.elemcount != i) {
32874aea 1187 error("tree really contains %d elements, count234 gave %d",
d2371c81 1188 ctx.elemcount, i);
1189 }
2d56b16f 1190}
1191
32874aea 1192void internal_addtest(void *elem, int index, void *realret)
1193{
2d56b16f 1194 int i, j;
d2371c81 1195 void *retval;
2d56b16f 1196
32874aea 1197 if (arraysize < arraylen + 1) {
1198 arraysize = arraylen + 1 + 256;
3d88e64d 1199 array = sresize(array, arraysize, void *);
2d56b16f 1200 }
1201
d2371c81 1202 i = index;
2d56b16f 1203 /* now i points to the first element >= elem */
32874aea 1204 retval = elem; /* expect elem returned (success) */
d2371c81 1205 for (j = arraylen; j > i; j--)
32874aea 1206 array[j] = array[j - 1];
1207 array[i] = elem; /* add elem to array */
d2371c81 1208 arraylen++;
2d56b16f 1209
2d56b16f 1210 if (realret != retval) {
32874aea 1211 error("add: retval was %p expected %p", realret, retval);
2d56b16f 1212 }
1213
1214 verify();
1215}
1216
32874aea 1217void addtest(void *elem)
1218{
2d56b16f 1219 int i;
d2371c81 1220 void *realret;
1221
1222 realret = add234(tree, elem);
2d56b16f 1223
1224 i = 0;
1225 while (i < arraylen && cmp(elem, array[i]) > 0)
32874aea 1226 i++;
d2371c81 1227 if (i < arraylen && !cmp(elem, array[i])) {
32874aea 1228 void *retval = array[i]; /* expect that returned not elem */
d2371c81 1229 if (realret != retval) {
1230 error("add: retval was %p expected %p", realret, retval);
1231 }
1232 } else
1233 internal_addtest(elem, i, realret);
1234}
1235
32874aea 1236void addpostest(void *elem, int i)
1237{
d2371c81 1238 void *realret;
1239
1240 realret = addpos234(tree, elem, i);
1241
1242 internal_addtest(elem, i, realret);
1243}
1244
32874aea 1245void delpostest(int i)
1246{
d2371c81 1247 int index = i;
1248 void *elem = array[i], *ret;
1249
1250 /* i points to the right element */
32874aea 1251 while (i < arraylen - 1) {
1252 array[i] = array[i + 1];
d2371c81 1253 i++;
2d56b16f 1254 }
d2371c81 1255 arraylen--; /* delete elem from array */
1256
1257 if (tree->cmp)
1258 ret = del234(tree, elem);
1259 else
1260 ret = delpos234(tree, index);
2d56b16f 1261
d2371c81 1262 if (ret != elem) {
1263 error("del returned %p, expected %p", ret, elem);
1264 }
2d56b16f 1265
1266 verify();
febd9a0f 1267}
2d56b16f 1268
32874aea 1269void deltest(void *elem)
1270{
d2371c81 1271 int i;
1272
1273 i = 0;
1274 while (i < arraylen && cmp(elem, array[i]) > 0)
32874aea 1275 i++;
d2371c81 1276 if (i >= arraylen || cmp(elem, array[i]) != 0)
32874aea 1277 return; /* don't do it! */
d2371c81 1278 delpostest(i);
1279}
1280
2d56b16f 1281/* A sample data set and test utility. Designed for pseudo-randomness,
1282 * and yet repeatability. */
1283
1284/*
1285 * This random number generator uses the `portable implementation'
1286 * given in ANSI C99 draft N869. It assumes `unsigned' is 32 bits;
1287 * change it if not.
1288 */
32874aea 1289int randomnumber(unsigned *seed)
1290{
2d56b16f 1291 *seed *= 1103515245;
1292 *seed += 12345;
1293 return ((*seed) / 65536) % 32768;
febd9a0f 1294}
1295
32874aea 1296int mycmp(void *av, void *bv)
1297{
1298 char const *a = (char const *) av;
1299 char const *b = (char const *) bv;
febd9a0f 1300 return strcmp(a, b);
1301}
1302
2d56b16f 1303#define lenof(x) ( sizeof((x)) / sizeof(*(x)) )
1304
1305char *strings[] = {
1306 "a", "ab", "absque", "coram", "de",
1307 "palam", "clam", "cum", "ex", "e",
1308 "sine", "tenus", "pro", "prae",
1309 "banana", "carrot", "cabbage", "broccoli", "onion", "zebra",
1310 "penguin", "blancmange", "pangolin", "whale", "hedgehog",
1311 "giraffe", "peanut", "bungee", "foo", "bar", "baz", "quux",
1312 "murfl", "spoo", "breen", "flarn", "octothorpe",
1313 "snail", "tiger", "elephant", "octopus", "warthog", "armadillo",
1314 "aardvark", "wyvern", "dragon", "elf", "dwarf", "orc", "goblin",
1315 "pixie", "basilisk", "warg", "ape", "lizard", "newt", "shopkeeper",
1316 "wand", "ring", "amulet"
1317};
1318
1319#define NSTR lenof(strings)
1320
32874aea 1321int findtest(void)
1322{
d2371c81 1323 const static int rels[] = {
1324 REL234_EQ, REL234_GE, REL234_LE, REL234_LT, REL234_GT
1325 };
1326 const static char *const relnames[] = {
1327 "EQ", "GE", "LE", "LT", "GT"
1328 };
1329 int i, j, rel, index;
1330 char *p, *ret, *realret, *realret2;
1331 int lo, hi, mid, c;
1332
1333 for (i = 0; i < NSTR; i++) {
1334 p = strings[i];
32874aea 1335 for (j = 0; j < sizeof(rels) / sizeof(*rels); j++) {
d2371c81 1336 rel = rels[j];
1337
32874aea 1338 lo = 0;
1339 hi = arraylen - 1;
d2371c81 1340 while (lo <= hi) {
1341 mid = (lo + hi) / 2;
1342 c = strcmp(p, array[mid]);
1343 if (c < 0)
32874aea 1344 hi = mid - 1;
d2371c81 1345 else if (c > 0)
32874aea 1346 lo = mid + 1;
d2371c81 1347 else
1348 break;
1349 }
1350
1351 if (c == 0) {
1352 if (rel == REL234_LT)
1353 ret = (mid > 0 ? array[--mid] : NULL);
1354 else if (rel == REL234_GT)
32874aea 1355 ret = (mid < arraylen - 1 ? array[++mid] : NULL);
d2371c81 1356 else
1357 ret = array[mid];
1358 } else {
32874aea 1359 assert(lo == hi + 1);
d2371c81 1360 if (rel == REL234_LT || rel == REL234_LE) {
1361 mid = hi;
1362 ret = (hi >= 0 ? array[hi] : NULL);
1363 } else if (rel == REL234_GT || rel == REL234_GE) {
1364 mid = lo;
1365 ret = (lo < arraylen ? array[lo] : NULL);
1366 } else
1367 ret = NULL;
1368 }
1369
1370 realret = findrelpos234(tree, p, NULL, rel, &index);
1371 if (realret != ret) {
1372 error("find(\"%s\",%s) gave %s should be %s",
1373 p, relnames[j], realret, ret);
1374 }
1375 if (realret && index != mid) {
1376 error("find(\"%s\",%s) gave %d should be %d",
1377 p, relnames[j], index, mid);
1378 }
1379 if (realret && rel == REL234_EQ) {
1380 realret2 = index234(tree, index);
1381 if (realret2 != realret) {
1382 error("find(\"%s\",%s) gave %s(%d) but %d -> %s",
1383 p, relnames[j], realret, index, index, realret2);
1384 }
1385 }
1386#if 0
1387 printf("find(\"%s\",%s) gave %s(%d)\n", p, relnames[j],
1388 realret, index);
1389#endif
1390 }
1391 }
1392
1393 realret = findrelpos234(tree, NULL, NULL, REL234_GT, &index);
1394 if (arraylen && (realret != array[0] || index != 0)) {
1395 error("find(NULL,GT) gave %s(%d) should be %s(0)",
1396 realret, index, array[0]);
1397 } else if (!arraylen && (realret != NULL)) {
32874aea 1398 error("find(NULL,GT) gave %s(%d) should be NULL", realret, index);
d2371c81 1399 }
1400
1401 realret = findrelpos234(tree, NULL, NULL, REL234_LT, &index);
32874aea 1402 if (arraylen
1403 && (realret != array[arraylen - 1] || index != arraylen - 1)) {
1404 error("find(NULL,LT) gave %s(%d) should be %s(0)", realret, index,
1405 array[arraylen - 1]);
d2371c81 1406 } else if (!arraylen && (realret != NULL)) {
32874aea 1407 error("find(NULL,LT) gave %s(%d) should be NULL", realret, index);
d2371c81 1408 }
1409}
1410
32874aea 1411int main(void)
1412{
2d56b16f 1413 int in[NSTR];
d2371c81 1414 int i, j, k;
2d56b16f 1415 unsigned seed = 0;
1416
32874aea 1417 for (i = 0; i < NSTR; i++)
1418 in[i] = 0;
2d56b16f 1419 array = NULL;
1420 arraylen = arraysize = 0;
1421 tree = newtree234(mycmp);
1422 cmp = mycmp;
1423
1424 verify();
1425 for (i = 0; i < 10000; i++) {
32874aea 1426 j = randomnumber(&seed);
1427 j %= NSTR;
1428 printf("trial: %d\n", i);
1429 if (in[j]) {
1430 printf("deleting %s (%d)\n", strings[j], j);
1431 deltest(strings[j]);
1432 in[j] = 0;
1433 } else {
1434 printf("adding %s (%d)\n", strings[j], j);
1435 addtest(strings[j]);
1436 in[j] = 1;
1437 }
d2371c81 1438 findtest();
2d56b16f 1439 }
1440
1441 while (arraylen > 0) {
32874aea 1442 j = randomnumber(&seed);
1443 j %= arraylen;
1444 deltest(array[j]);
2d56b16f 1445 }
1446
d2371c81 1447 freetree234(tree);
1448
1449 /*
1450 * Now try an unsorted tree. We don't really need to test
1451 * delpos234 because we know del234 is based on it, so it's
1452 * already been tested in the above sorted-tree code; but for
1453 * completeness we'll use it to tear down our unsorted tree
1454 * once we've built it.
1455 */
1456 tree = newtree234(NULL);
1457 cmp = NULL;
1458 verify();
1459 for (i = 0; i < 1000; i++) {
1460 printf("trial: %d\n", i);
1461 j = randomnumber(&seed);
1462 j %= NSTR;
1463 k = randomnumber(&seed);
32874aea 1464 k %= count234(tree) + 1;
d2371c81 1465 printf("adding string %s at index %d\n", strings[j], k);
1466 addpostest(strings[j], k);
1467 }
1468 while (count234(tree) > 0) {
1469 printf("cleanup: tree size %d\n", count234(tree));
1470 j = randomnumber(&seed);
1471 j %= count234(tree);
1472 printf("deleting string %s from index %d\n", array[j], j);
1473 delpostest(j);
1474 }
1475
2d56b16f 1476 return 0;
febd9a0f 1477}
2d56b16f 1478
febd9a0f 1479#endif