diff options
Diffstat (limited to 'apps/plugins/puzzles/src/tree234.c')
-rw-r--r-- | apps/plugins/puzzles/src/tree234.c | 782 |
1 files changed, 14 insertions, 768 deletions
diff --git a/apps/plugins/puzzles/src/tree234.c b/apps/plugins/puzzles/src/tree234.c index ad8eb047cd..ef2c3ffaf7 100644 --- a/apps/plugins/puzzles/src/tree234.c +++ b/apps/plugins/puzzles/src/tree234.c | |||
@@ -29,33 +29,25 @@ | |||
29 | #include <stdlib.h> | 29 | #include <stdlib.h> |
30 | #include <assert.h> | 30 | #include <assert.h> |
31 | 31 | ||
32 | #define TREE234_INTERNALS | ||
32 | #include "tree234.h" | 33 | #include "tree234.h" |
33 | 34 | ||
34 | #include "puzzles.h" /* for smalloc/sfree */ | 35 | #include "puzzles.h" /* for smalloc/sfree */ |
35 | 36 | ||
36 | #ifdef TEST | 37 | #ifdef DEBUG_TREE234 |
37 | #define LOG(x) (printf x) | 38 | #include <stdarg.h> |
38 | #define smalloc malloc | 39 | static void logprintf(const char *fmt, ...) |
39 | #define srealloc realloc | 40 | { |
40 | #define sfree free | 41 | va_list ap; |
42 | va_start(ap, fmt); | ||
43 | vprintf(fmt, ap); | ||
44 | va_end(ap); | ||
45 | } | ||
46 | #define LOG(x) (logprintf x) | ||
41 | #else | 47 | #else |
42 | #define LOG(x) | 48 | #define LOG(x) |
43 | #endif | 49 | #endif |
44 | 50 | ||
45 | typedef struct node234_Tag node234; | ||
46 | |||
47 | struct tree234_Tag { | ||
48 | node234 *root; | ||
49 | cmpfn234 cmp; | ||
50 | }; | ||
51 | |||
52 | struct node234_Tag { | ||
53 | node234 *parent; | ||
54 | node234 *kids[4]; | ||
55 | int counts[4]; | ||
56 | void *elems[3]; | ||
57 | }; | ||
58 | |||
59 | /* | 51 | /* |
60 | * Create a 2-3-4 tree. | 52 | * Create a 2-3-4 tree. |
61 | */ | 53 | */ |
@@ -327,7 +319,7 @@ static void *add234_internal(tree234 *t, void *e, int index) { | |||
327 | } | 319 | } |
328 | 320 | ||
329 | n = t->root; | 321 | n = t->root; |
330 | while (n) { | 322 | do { |
331 | LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", | 323 | LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", |
332 | n, | 324 | n, |
333 | n->kids[0], n->counts[0], n->elems[0], | 325 | n->kids[0], n->counts[0], n->elems[0], |
@@ -380,7 +372,7 @@ static void *add234_internal(tree234 *t, void *e, int index) { | |||
380 | if (!n->kids[ki]) | 372 | if (!n->kids[ki]) |
381 | break; | 373 | break; |
382 | n = n->kids[ki]; | 374 | n = n->kids[ki]; |
383 | } | 375 | } while (n); |
384 | 376 | ||
385 | add234_insert(NULL, e, NULL, &t->root, n, ki); | 377 | add234_insert(NULL, e, NULL, &t->root, n, ki); |
386 | 378 | ||
@@ -1104,7 +1096,7 @@ static node234 *join234_internal(node234 *left, void *sep, | |||
1104 | 1096 | ||
1105 | return root; | 1097 | return root; |
1106 | } | 1098 | } |
1107 | static int height234(tree234 *t) { | 1099 | int height234(tree234 *t) { |
1108 | int level = 0; | 1100 | int level = 0; |
1109 | node234 *n = t->root; | 1101 | node234 *n = t->root; |
1110 | while (n) { | 1102 | while (n) { |
@@ -1452,749 +1444,3 @@ tree234 *copytree234(tree234 *t, copyfn234 copyfn, void *copyfnstate) { | |||
1452 | 1444 | ||
1453 | return t2; | 1445 | return t2; |
1454 | } | 1446 | } |
1455 | |||
1456 | #ifdef TEST | ||
1457 | |||
1458 | /* | ||
1459 | * Test code for the 2-3-4 tree. This code maintains an alternative | ||
1460 | * representation of the data in the tree, in an array (using the | ||
1461 | * obvious and slow insert and delete functions). After each tree | ||
1462 | * operation, the verify() function is called, which ensures all | ||
1463 | * the tree properties are preserved: | ||
1464 | * - node->child->parent always equals node | ||
1465 | * - tree->root->parent always equals NULL | ||
1466 | * - number of kids == 0 or number of elements + 1; | ||
1467 | * - tree has the same depth everywhere | ||
1468 | * - every node has at least one element | ||
1469 | * - subtree element counts are accurate | ||
1470 | * - any NULL kid pointer is accompanied by a zero count | ||
1471 | * - in a sorted tree: ordering property between elements of a | ||
1472 | * node and elements of its children is preserved | ||
1473 | * and also ensures the list represented by the tree is the same | ||
1474 | * list it should be. (This last check also doubly verifies the | ||
1475 | * ordering properties, because the `same list it should be' is by | ||
1476 | * definition correctly ordered. It also ensures all nodes are | ||
1477 | * distinct, because the enum functions would get caught in a loop | ||
1478 | * if not.) | ||
1479 | */ | ||
1480 | |||
1481 | #include <string.h> | ||
1482 | #include <stdarg.h> | ||
1483 | |||
1484 | #define srealloc realloc | ||
1485 | |||
1486 | /* | ||
1487 | * Error reporting function. | ||
1488 | */ | ||
1489 | void error(char *fmt, ...) { | ||
1490 | va_list ap; | ||
1491 | printf("ERROR: "); | ||
1492 | va_start(ap, fmt); | ||
1493 | vfprintf(stdout, fmt, ap); | ||
1494 | va_end(ap); | ||
1495 | printf("\n"); | ||
1496 | } | ||
1497 | |||
1498 | /* The array representation of the data. */ | ||
1499 | void **array; | ||
1500 | int arraylen, arraysize; | ||
1501 | cmpfn234 cmp; | ||
1502 | |||
1503 | /* The tree representation of the same data. */ | ||
1504 | tree234 *tree; | ||
1505 | |||
1506 | /* | ||
1507 | * Routines to provide a diagnostic printout of a tree. Currently | ||
1508 | * relies on every element in the tree being a one-character string | ||
1509 | * :-) | ||
1510 | */ | ||
1511 | typedef struct { | ||
1512 | char **levels; | ||
1513 | } dispctx; | ||
1514 | |||
1515 | int dispnode(node234 *n, int level, dispctx *ctx) { | ||
1516 | if (level == 0) { | ||
1517 | int xpos = strlen(ctx->levels[0]); | ||
1518 | int len; | ||
1519 | |||
1520 | if (n->elems[2]) | ||
1521 | len = sprintf(ctx->levels[0]+xpos, " %s%s%s", | ||
1522 | n->elems[0], n->elems[1], n->elems[2]); | ||
1523 | else if (n->elems[1]) | ||
1524 | len = sprintf(ctx->levels[0]+xpos, " %s%s", | ||
1525 | n->elems[0], n->elems[1]); | ||
1526 | else | ||
1527 | len = sprintf(ctx->levels[0]+xpos, " %s", | ||
1528 | n->elems[0]); | ||
1529 | return xpos + 1 + (len-1) / 2; | ||
1530 | } else { | ||
1531 | int xpos[4], nkids; | ||
1532 | int nodelen, mypos, myleft, x, i; | ||
1533 | |||
1534 | xpos[0] = dispnode(n->kids[0], level-3, ctx); | ||
1535 | xpos[1] = dispnode(n->kids[1], level-3, ctx); | ||
1536 | nkids = 2; | ||
1537 | if (n->kids[2]) { | ||
1538 | xpos[2] = dispnode(n->kids[2], level-3, ctx); | ||
1539 | nkids = 3; | ||
1540 | } | ||
1541 | if (n->kids[3]) { | ||
1542 | xpos[3] = dispnode(n->kids[3], level-3, ctx); | ||
1543 | nkids = 4; | ||
1544 | } | ||
1545 | |||
1546 | if (nkids == 4) | ||
1547 | mypos = (xpos[1] + xpos[2]) / 2; | ||
1548 | else if (nkids == 3) | ||
1549 | mypos = xpos[1]; | ||
1550 | else | ||
1551 | mypos = (xpos[0] + xpos[1]) / 2; | ||
1552 | nodelen = nkids * 2 - 1; | ||
1553 | myleft = mypos - ((nodelen-1)/2); | ||
1554 | assert(myleft >= xpos[0]); | ||
1555 | assert(myleft + nodelen-1 <= xpos[nkids-1]); | ||
1556 | |||
1557 | x = strlen(ctx->levels[level]); | ||
1558 | while (x <= xpos[0] && x < myleft) | ||
1559 | ctx->levels[level][x++] = ' '; | ||
1560 | while (x < myleft) | ||
1561 | ctx->levels[level][x++] = '_'; | ||
1562 | if (nkids==4) | ||
1563 | x += sprintf(ctx->levels[level]+x, ".%s.%s.%s.", | ||
1564 | n->elems[0], n->elems[1], n->elems[2]); | ||
1565 | else if (nkids==3) | ||
1566 | x += sprintf(ctx->levels[level]+x, ".%s.%s.", | ||
1567 | n->elems[0], n->elems[1]); | ||
1568 | else | ||
1569 | x += sprintf(ctx->levels[level]+x, ".%s.", | ||
1570 | n->elems[0]); | ||
1571 | while (x < xpos[nkids-1]) | ||
1572 | ctx->levels[level][x++] = '_'; | ||
1573 | ctx->levels[level][x] = '\0'; | ||
1574 | |||
1575 | x = strlen(ctx->levels[level-1]); | ||
1576 | for (i = 0; i < nkids; i++) { | ||
1577 | int rpos, pos; | ||
1578 | rpos = xpos[i]; | ||
1579 | if (i > 0 && i < nkids-1) | ||
1580 | pos = myleft + 2*i; | ||
1581 | else | ||
1582 | pos = rpos; | ||
1583 | if (rpos < pos) | ||
1584 | rpos++; | ||
1585 | while (x < pos && x < rpos) | ||
1586 | ctx->levels[level-1][x++] = ' '; | ||
1587 | if (x == pos) | ||
1588 | ctx->levels[level-1][x++] = '|'; | ||
1589 | while (x < pos || x < rpos) | ||
1590 | ctx->levels[level-1][x++] = '_'; | ||
1591 | if (x == pos) | ||
1592 | ctx->levels[level-1][x++] = '|'; | ||
1593 | } | ||
1594 | ctx->levels[level-1][x] = '\0'; | ||
1595 | |||
1596 | x = strlen(ctx->levels[level-2]); | ||
1597 | for (i = 0; i < nkids; i++) { | ||
1598 | int rpos = xpos[i]; | ||
1599 | |||
1600 | while (x < rpos) | ||
1601 | ctx->levels[level-2][x++] = ' '; | ||
1602 | ctx->levels[level-2][x++] = '|'; | ||
1603 | } | ||
1604 | ctx->levels[level-2][x] = '\0'; | ||
1605 | |||
1606 | return mypos; | ||
1607 | } | ||
1608 | } | ||
1609 | |||
1610 | void disptree(tree234 *t) { | ||
1611 | dispctx ctx; | ||
1612 | char *leveldata; | ||
1613 | int width = count234(t); | ||
1614 | int ht = height234(t) * 3 - 2; | ||
1615 | int i; | ||
1616 | |||
1617 | if (!t->root) { | ||
1618 | printf("[empty tree]\n"); | ||
1619 | } | ||
1620 | |||
1621 | leveldata = smalloc(ht * (width+2)); | ||
1622 | ctx.levels = smalloc(ht * sizeof(char *)); | ||
1623 | for (i = 0; i < ht; i++) { | ||
1624 | ctx.levels[i] = leveldata + i * (width+2); | ||
1625 | ctx.levels[i][0] = '\0'; | ||
1626 | } | ||
1627 | |||
1628 | (void) dispnode(t->root, ht-1, &ctx); | ||
1629 | |||
1630 | for (i = ht; i-- ;) | ||
1631 | printf("%s\n", ctx.levels[i]); | ||
1632 | |||
1633 | sfree(ctx.levels); | ||
1634 | sfree(leveldata); | ||
1635 | } | ||
1636 | |||
1637 | typedef struct { | ||
1638 | int treedepth; | ||
1639 | int elemcount; | ||
1640 | } chkctx; | ||
1641 | |||
1642 | int chknode(chkctx *ctx, int level, node234 *node, | ||
1643 | void *lowbound, void *highbound) { | ||
1644 | int nkids, nelems; | ||
1645 | int i; | ||
1646 | int count; | ||
1647 | |||
1648 | /* Count the non-NULL kids. */ | ||
1649 | for (nkids = 0; nkids < 4 && node->kids[nkids]; nkids++); | ||
1650 | /* Ensure no kids beyond the first NULL are non-NULL. */ | ||
1651 | for (i = nkids; i < 4; i++) | ||
1652 | if (node->kids[i]) { | ||
1653 | error("node %p: nkids=%d but kids[%d] non-NULL", | ||
1654 | node, nkids, i); | ||
1655 | } else if (node->counts[i]) { | ||
1656 | error("node %p: kids[%d] NULL but count[%d]=%d nonzero", | ||
1657 | node, i, i, node->counts[i]); | ||
1658 | } | ||
1659 | |||
1660 | /* Count the non-NULL elements. */ | ||
1661 | for (nelems = 0; nelems < 3 && node->elems[nelems]; nelems++); | ||
1662 | /* Ensure no elements beyond the first NULL are non-NULL. */ | ||
1663 | for (i = nelems; i < 3; i++) | ||
1664 | if (node->elems[i]) { | ||
1665 | error("node %p: nelems=%d but elems[%d] non-NULL", | ||
1666 | node, nelems, i); | ||
1667 | } | ||
1668 | |||
1669 | if (nkids == 0) { | ||
1670 | /* | ||
1671 | * If nkids==0, this is a leaf node; verify that the tree | ||
1672 | * depth is the same everywhere. | ||
1673 | */ | ||
1674 | if (ctx->treedepth < 0) | ||
1675 | ctx->treedepth = level; /* we didn't know the depth yet */ | ||
1676 | else if (ctx->treedepth != level) | ||
1677 | error("node %p: leaf at depth %d, previously seen depth %d", | ||
1678 | node, level, ctx->treedepth); | ||
1679 | } else { | ||
1680 | /* | ||
1681 | * If nkids != 0, then it should be nelems+1, unless nelems | ||
1682 | * is 0 in which case nkids should also be 0 (and so we | ||
1683 | * shouldn't be in this condition at all). | ||
1684 | */ | ||
1685 | int shouldkids = (nelems ? nelems+1 : 0); | ||
1686 | if (nkids != shouldkids) { | ||
1687 | error("node %p: %d elems should mean %d kids but has %d", | ||
1688 | node, nelems, shouldkids, nkids); | ||
1689 | } | ||
1690 | } | ||
1691 | |||
1692 | /* | ||
1693 | * nelems should be at least 1. | ||
1694 | */ | ||
1695 | if (nelems == 0) { | ||
1696 | error("node %p: no elems", node, nkids); | ||
1697 | } | ||
1698 | |||
1699 | /* | ||
1700 | * Add nelems to the running element count of the whole tree. | ||
1701 | */ | ||
1702 | ctx->elemcount += nelems; | ||
1703 | |||
1704 | /* | ||
1705 | * Check ordering property: all elements should be strictly > | ||
1706 | * lowbound, strictly < highbound, and strictly < each other in | ||
1707 | * sequence. (lowbound and highbound are NULL at edges of tree | ||
1708 | * - both NULL at root node - and NULL is considered to be < | ||
1709 | * everything and > everything. IYSWIM.) | ||
1710 | */ | ||
1711 | if (cmp) { | ||
1712 | for (i = -1; i < nelems; i++) { | ||
1713 | void *lower = (i == -1 ? lowbound : node->elems[i]); | ||
1714 | void *higher = (i+1 == nelems ? highbound : node->elems[i+1]); | ||
1715 | if (lower && higher && cmp(lower, higher) >= 0) { | ||
1716 | error("node %p: kid comparison [%d=%s,%d=%s] failed", | ||
1717 | node, i, lower, i+1, higher); | ||
1718 | } | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1722 | /* | ||
1723 | * Check parent pointers: all non-NULL kids should have a | ||
1724 | * parent pointer coming back to this node. | ||
1725 | */ | ||
1726 | for (i = 0; i < nkids; i++) | ||
1727 | if (node->kids[i]->parent != node) { | ||
1728 | error("node %p kid %d: parent ptr is %p not %p", | ||
1729 | node, i, node->kids[i]->parent, node); | ||
1730 | } | ||
1731 | |||
1732 | |||
1733 | /* | ||
1734 | * Now (finally!) recurse into subtrees. | ||
1735 | */ | ||
1736 | count = nelems; | ||
1737 | |||
1738 | for (i = 0; i < nkids; i++) { | ||
1739 | void *lower = (i == 0 ? lowbound : node->elems[i-1]); | ||
1740 | void *higher = (i >= nelems ? highbound : node->elems[i]); | ||
1741 | int subcount = chknode(ctx, level+1, node->kids[i], lower, higher); | ||
1742 | if (node->counts[i] != subcount) { | ||
1743 | error("node %p kid %d: count says %d, subtree really has %d", | ||
1744 | node, i, node->counts[i], subcount); | ||
1745 | } | ||
1746 | count += subcount; | ||
1747 | } | ||
1748 | |||
1749 | return count; | ||
1750 | } | ||
1751 | |||
1752 | void verifytree(tree234 *tree, void **array, int arraylen) { | ||
1753 | chkctx ctx; | ||
1754 | int i; | ||
1755 | void *p; | ||
1756 | |||
1757 | ctx.treedepth = -1; /* depth unknown yet */ | ||
1758 | ctx.elemcount = 0; /* no elements seen yet */ | ||
1759 | /* | ||
1760 | * Verify validity of tree properties. | ||
1761 | */ | ||
1762 | if (tree->root) { | ||
1763 | if (tree->root->parent != NULL) | ||
1764 | error("root->parent is %p should be null", tree->root->parent); | ||
1765 | chknode(&ctx, 0, tree->root, NULL, NULL); | ||
1766 | } | ||
1767 | printf("tree depth: %d\n", ctx.treedepth); | ||
1768 | /* | ||
1769 | * Enumerate the tree and ensure it matches up to the array. | ||
1770 | */ | ||
1771 | for (i = 0; NULL != (p = index234(tree, i)); i++) { | ||
1772 | if (i >= arraylen) | ||
1773 | error("tree contains more than %d elements", arraylen); | ||
1774 | if (array[i] != p) | ||
1775 | error("enum at position %d: array says %s, tree says %s", | ||
1776 | i, array[i], p); | ||
1777 | } | ||
1778 | if (ctx.elemcount != i) { | ||
1779 | error("tree really contains %d elements, enum gave %d", | ||
1780 | ctx.elemcount, i); | ||
1781 | } | ||
1782 | if (i < arraylen) { | ||
1783 | error("enum gave only %d elements, array has %d", i, arraylen); | ||
1784 | } | ||
1785 | i = count234(tree); | ||
1786 | if (ctx.elemcount != i) { | ||
1787 | error("tree really contains %d elements, count234 gave %d", | ||
1788 | ctx.elemcount, i); | ||
1789 | } | ||
1790 | } | ||
1791 | void verify(void) { verifytree(tree, array, arraylen); } | ||
1792 | |||
1793 | void internal_addtest(void *elem, int index, void *realret) { | ||
1794 | int i, j; | ||
1795 | void *retval; | ||
1796 | |||
1797 | if (arraysize < arraylen+1) { | ||
1798 | arraysize = arraylen+1+256; | ||
1799 | array = (array == NULL ? smalloc(arraysize*sizeof(*array)) : | ||
1800 | srealloc(array, arraysize*sizeof(*array))); | ||
1801 | } | ||
1802 | |||
1803 | i = index; | ||
1804 | /* now i points to the first element >= elem */ | ||
1805 | retval = elem; /* expect elem returned (success) */ | ||
1806 | for (j = arraylen; j > i; j--) | ||
1807 | array[j] = array[j-1]; | ||
1808 | array[i] = elem; /* add elem to array */ | ||
1809 | arraylen++; | ||
1810 | |||
1811 | if (realret != retval) { | ||
1812 | error("add: retval was %p expected %p", realret, retval); | ||
1813 | } | ||
1814 | |||
1815 | verify(); | ||
1816 | } | ||
1817 | |||
1818 | void addtest(void *elem) { | ||
1819 | int i; | ||
1820 | void *realret; | ||
1821 | |||
1822 | realret = add234(tree, elem); | ||
1823 | |||
1824 | i = 0; | ||
1825 | while (i < arraylen && cmp(elem, array[i]) > 0) | ||
1826 | i++; | ||
1827 | if (i < arraylen && !cmp(elem, array[i])) { | ||
1828 | void *retval = array[i]; /* expect that returned not elem */ | ||
1829 | if (realret != retval) { | ||
1830 | error("add: retval was %p expected %p", realret, retval); | ||
1831 | } | ||
1832 | } else | ||
1833 | internal_addtest(elem, i, realret); | ||
1834 | } | ||
1835 | |||
1836 | void addpostest(void *elem, int i) { | ||
1837 | void *realret; | ||
1838 | |||
1839 | realret = addpos234(tree, elem, i); | ||
1840 | |||
1841 | internal_addtest(elem, i, realret); | ||
1842 | } | ||
1843 | |||
1844 | void delpostest(int i) { | ||
1845 | int index = i; | ||
1846 | void *elem = array[i], *ret; | ||
1847 | |||
1848 | /* i points to the right element */ | ||
1849 | while (i < arraylen-1) { | ||
1850 | array[i] = array[i+1]; | ||
1851 | i++; | ||
1852 | } | ||
1853 | arraylen--; /* delete elem from array */ | ||
1854 | |||
1855 | if (tree->cmp) | ||
1856 | ret = del234(tree, elem); | ||
1857 | else | ||
1858 | ret = delpos234(tree, index); | ||
1859 | |||
1860 | if (ret != elem) { | ||
1861 | error("del returned %p, expected %p", ret, elem); | ||
1862 | } | ||
1863 | |||
1864 | verify(); | ||
1865 | } | ||
1866 | |||
1867 | void deltest(void *elem) { | ||
1868 | int i; | ||
1869 | |||
1870 | i = 0; | ||
1871 | while (i < arraylen && cmp(elem, array[i]) > 0) | ||
1872 | i++; | ||
1873 | if (i >= arraylen || cmp(elem, array[i]) != 0) | ||
1874 | return; /* don't do it! */ | ||
1875 | delpostest(i); | ||
1876 | } | ||
1877 | |||
1878 | /* A sample data set and test utility. Designed for pseudo-randomness, | ||
1879 | * and yet repeatability. */ | ||
1880 | |||
1881 | /* | ||
1882 | * This random number generator uses the `portable implementation' | ||
1883 | * given in ANSI C99 draft N869. It assumes `unsigned' is 32 bits; | ||
1884 | * change it if not. | ||
1885 | */ | ||
1886 | int randomnumber(unsigned *seed) { | ||
1887 | *seed *= 1103515245; | ||
1888 | *seed += 12345; | ||
1889 | return ((*seed) / 65536) % 32768; | ||
1890 | } | ||
1891 | |||
1892 | int mycmp(void *av, void *bv) { | ||
1893 | char const *a = (char const *)av; | ||
1894 | char const *b = (char const *)bv; | ||
1895 | return strcmp(a, b); | ||
1896 | } | ||
1897 | |||
1898 | char *strings[] = { | ||
1899 | "0", "2", "3", "I", "K", "d", "H", "J", "Q", "N", "n", "q", "j", "i", | ||
1900 | "7", "G", "F", "D", "b", "x", "g", "B", "e", "v", "V", "T", "f", "E", | ||
1901 | "S", "8", "A", "k", "X", "p", "C", "R", "a", "o", "r", "O", "Z", "u", | ||
1902 | "6", "1", "w", "L", "P", "M", "c", "U", "h", "9", "t", "5", "W", "Y", | ||
1903 | "m", "s", "l", "4", | ||
1904 | #if 0 | ||
1905 | "a", "ab", "absque", "coram", "de", | ||
1906 | "palam", "clam", "cum", "ex", "e", | ||
1907 | "sine", "tenus", "pro", "prae", | ||
1908 | "banana", "carrot", "cabbage", "broccoli", "onion", "zebra", | ||
1909 | "penguin", "blancmange", "pangolin", "whale", "hedgehog", | ||
1910 | "giraffe", "peanut", "bungee", "foo", "bar", "baz", "quux", | ||
1911 | "murfl", "spoo", "breen", "flarn", "octothorpe", | ||
1912 | "snail", "tiger", "elephant", "octopus", "warthog", "armadillo", | ||
1913 | "aardvark", "wyvern", "dragon", "elf", "dwarf", "orc", "goblin", | ||
1914 | "pixie", "basilisk", "warg", "ape", "lizard", "newt", "shopkeeper", | ||
1915 | "wand", "ring", "amulet" | ||
1916 | #endif | ||
1917 | }; | ||
1918 | |||
1919 | #define NSTR lenof(strings) | ||
1920 | |||
1921 | void findtest(void) { | ||
1922 | static const int rels[] = { | ||
1923 | REL234_EQ, REL234_GE, REL234_LE, REL234_LT, REL234_GT | ||
1924 | }; | ||
1925 | static const char *const relnames[] = { | ||
1926 | "EQ", "GE", "LE", "LT", "GT" | ||
1927 | }; | ||
1928 | int i, j, rel, index; | ||
1929 | char *p, *ret, *realret, *realret2; | ||
1930 | int lo, hi, mid, c; | ||
1931 | |||
1932 | for (i = 0; i < (int)NSTR; i++) { | ||
1933 | p = strings[i]; | ||
1934 | for (j = 0; j < (int)(sizeof(rels)/sizeof(*rels)); j++) { | ||
1935 | rel = rels[j]; | ||
1936 | |||
1937 | lo = 0; hi = arraylen-1; | ||
1938 | while (lo <= hi) { | ||
1939 | mid = (lo + hi) / 2; | ||
1940 | c = strcmp(p, array[mid]); | ||
1941 | if (c < 0) | ||
1942 | hi = mid-1; | ||
1943 | else if (c > 0) | ||
1944 | lo = mid+1; | ||
1945 | else | ||
1946 | break; | ||
1947 | } | ||
1948 | |||
1949 | if (c == 0) { | ||
1950 | if (rel == REL234_LT) | ||
1951 | ret = (mid > 0 ? array[--mid] : NULL); | ||
1952 | else if (rel == REL234_GT) | ||
1953 | ret = (mid < arraylen-1 ? array[++mid] : NULL); | ||
1954 | else | ||
1955 | ret = array[mid]; | ||
1956 | } else { | ||
1957 | assert(lo == hi+1); | ||
1958 | if (rel == REL234_LT || rel == REL234_LE) { | ||
1959 | mid = hi; | ||
1960 | ret = (hi >= 0 ? array[hi] : NULL); | ||
1961 | } else if (rel == REL234_GT || rel == REL234_GE) { | ||
1962 | mid = lo; | ||
1963 | ret = (lo < arraylen ? array[lo] : NULL); | ||
1964 | } else | ||
1965 | ret = NULL; | ||
1966 | } | ||
1967 | |||
1968 | realret = findrelpos234(tree, p, NULL, rel, &index); | ||
1969 | if (realret != ret) { | ||
1970 | error("find(\"%s\",%s) gave %s should be %s", | ||
1971 | p, relnames[j], realret, ret); | ||
1972 | } | ||
1973 | if (realret && index != mid) { | ||
1974 | error("find(\"%s\",%s) gave %d should be %d", | ||
1975 | p, relnames[j], index, mid); | ||
1976 | } | ||
1977 | if (realret && rel == REL234_EQ) { | ||
1978 | realret2 = index234(tree, index); | ||
1979 | if (realret2 != realret) { | ||
1980 | error("find(\"%s\",%s) gave %s(%d) but %d -> %s", | ||
1981 | p, relnames[j], realret, index, index, realret2); | ||
1982 | } | ||
1983 | } | ||
1984 | #if 0 | ||
1985 | printf("find(\"%s\",%s) gave %s(%d)\n", p, relnames[j], | ||
1986 | realret, index); | ||
1987 | #endif | ||
1988 | } | ||
1989 | } | ||
1990 | |||
1991 | realret = findrelpos234(tree, NULL, NULL, REL234_GT, &index); | ||
1992 | if (arraylen && (realret != array[0] || index != 0)) { | ||
1993 | error("find(NULL,GT) gave %s(%d) should be %s(0)", | ||
1994 | realret, index, array[0]); | ||
1995 | } else if (!arraylen && (realret != NULL)) { | ||
1996 | error("find(NULL,GT) gave %s(%d) should be NULL", | ||
1997 | realret, index); | ||
1998 | } | ||
1999 | |||
2000 | realret = findrelpos234(tree, NULL, NULL, REL234_LT, &index); | ||
2001 | if (arraylen && (realret != array[arraylen-1] || index != arraylen-1)) { | ||
2002 | error("find(NULL,LT) gave %s(%d) should be %s(0)", | ||
2003 | realret, index, array[arraylen-1]); | ||
2004 | } else if (!arraylen && (realret != NULL)) { | ||
2005 | error("find(NULL,LT) gave %s(%d) should be NULL", | ||
2006 | realret, index); | ||
2007 | } | ||
2008 | } | ||
2009 | |||
2010 | void splittest(tree234 *tree, void **array, int arraylen) { | ||
2011 | int i; | ||
2012 | tree234 *tree3, *tree4; | ||
2013 | for (i = 0; i <= arraylen; i++) { | ||
2014 | tree3 = copytree234(tree, NULL, NULL); | ||
2015 | tree4 = splitpos234(tree3, i, false); | ||
2016 | verifytree(tree3, array, i); | ||
2017 | verifytree(tree4, array+i, arraylen-i); | ||
2018 | join234(tree3, tree4); | ||
2019 | freetree234(tree4); /* left empty by join */ | ||
2020 | verifytree(tree3, array, arraylen); | ||
2021 | freetree234(tree3); | ||
2022 | } | ||
2023 | } | ||
2024 | |||
2025 | int main(void) { | ||
2026 | int in[NSTR]; | ||
2027 | int i, j, k; | ||
2028 | int tworoot, tmplen; | ||
2029 | unsigned seed = 0; | ||
2030 | tree234 *tree2, *tree3, *tree4; | ||
2031 | int c; | ||
2032 | |||
2033 | setvbuf(stdout, NULL, _IOLBF, 0); | ||
2034 | |||
2035 | for (i = 0; i < (int)NSTR; i++) in[i] = 0; | ||
2036 | array = NULL; | ||
2037 | arraylen = arraysize = 0; | ||
2038 | tree = newtree234(mycmp); | ||
2039 | cmp = mycmp; | ||
2040 | |||
2041 | verify(); | ||
2042 | for (i = 0; i < 10000; i++) { | ||
2043 | j = randomnumber(&seed); | ||
2044 | j %= NSTR; | ||
2045 | printf("trial: %d\n", i); | ||
2046 | if (in[j]) { | ||
2047 | printf("deleting %s (%d)\n", strings[j], j); | ||
2048 | deltest(strings[j]); | ||
2049 | in[j] = 0; | ||
2050 | } else { | ||
2051 | printf("adding %s (%d)\n", strings[j], j); | ||
2052 | addtest(strings[j]); | ||
2053 | in[j] = 1; | ||
2054 | } | ||
2055 | disptree(tree); | ||
2056 | findtest(); | ||
2057 | } | ||
2058 | |||
2059 | while (arraylen > 0) { | ||
2060 | j = randomnumber(&seed); | ||
2061 | j %= arraylen; | ||
2062 | deltest(array[j]); | ||
2063 | } | ||
2064 | |||
2065 | freetree234(tree); | ||
2066 | |||
2067 | /* | ||
2068 | * Now try an unsorted tree. We don't really need to test | ||
2069 | * delpos234 because we know del234 is based on it, so it's | ||
2070 | * already been tested in the above sorted-tree code; but for | ||
2071 | * completeness we'll use it to tear down our unsorted tree | ||
2072 | * once we've built it. | ||
2073 | */ | ||
2074 | tree = newtree234(NULL); | ||
2075 | cmp = NULL; | ||
2076 | verify(); | ||
2077 | for (i = 0; i < 1000; i++) { | ||
2078 | printf("trial: %d\n", i); | ||
2079 | j = randomnumber(&seed); | ||
2080 | j %= NSTR; | ||
2081 | k = randomnumber(&seed); | ||
2082 | k %= count234(tree)+1; | ||
2083 | printf("adding string %s at index %d\n", strings[j], k); | ||
2084 | addpostest(strings[j], k); | ||
2085 | } | ||
2086 | |||
2087 | /* | ||
2088 | * While we have this tree in its full form, we'll take a copy | ||
2089 | * of it to use in split and join testing. | ||
2090 | */ | ||
2091 | tree2 = copytree234(tree, NULL, NULL); | ||
2092 | verifytree(tree2, array, arraylen);/* check the copy is accurate */ | ||
2093 | /* | ||
2094 | * Split tests. Split the tree at every possible point and | ||
2095 | * check the resulting subtrees. | ||
2096 | */ | ||
2097 | tworoot = (!tree2->root->elems[1]);/* see if it has a 2-root */ | ||
2098 | splittest(tree2, array, arraylen); | ||
2099 | /* | ||
2100 | * Now do the split test again, but on a tree that has a 2-root | ||
2101 | * (if the previous one didn't) or doesn't (if the previous one | ||
2102 | * did). | ||
2103 | */ | ||
2104 | tmplen = arraylen; | ||
2105 | while ((!tree2->root->elems[1]) == tworoot) { | ||
2106 | delpos234(tree2, --tmplen); | ||
2107 | } | ||
2108 | printf("now trying splits on second tree\n"); | ||
2109 | splittest(tree2, array, tmplen); | ||
2110 | freetree234(tree2); | ||
2111 | |||
2112 | /* | ||
2113 | * Back to the main testing of uncounted trees. | ||
2114 | */ | ||
2115 | while (count234(tree) > 0) { | ||
2116 | printf("cleanup: tree size %d\n", count234(tree)); | ||
2117 | j = randomnumber(&seed); | ||
2118 | j %= count234(tree); | ||
2119 | printf("deleting string %s from index %d\n", (char *)array[j], j); | ||
2120 | delpostest(j); | ||
2121 | } | ||
2122 | freetree234(tree); | ||
2123 | |||
2124 | /* | ||
2125 | * Finally, do some testing on split/join on _sorted_ trees. At | ||
2126 | * the same time, we'll be testing split on very small trees. | ||
2127 | */ | ||
2128 | tree = newtree234(mycmp); | ||
2129 | cmp = mycmp; | ||
2130 | arraylen = 0; | ||
2131 | for (i = 0; i < 17; i++) { | ||
2132 | tree2 = copytree234(tree, NULL, NULL); | ||
2133 | splittest(tree2, array, arraylen); | ||
2134 | freetree234(tree2); | ||
2135 | if (i < 16) | ||
2136 | addtest(strings[i]); | ||
2137 | } | ||
2138 | freetree234(tree); | ||
2139 | |||
2140 | /* | ||
2141 | * Test silly cases of join: join(emptytree, emptytree), and | ||
2142 | * also ensure join correctly spots when sorted trees fail the | ||
2143 | * ordering constraint. | ||
2144 | */ | ||
2145 | tree = newtree234(mycmp); | ||
2146 | tree2 = newtree234(mycmp); | ||
2147 | tree3 = newtree234(mycmp); | ||
2148 | tree4 = newtree234(mycmp); | ||
2149 | assert(mycmp(strings[0], strings[1]) < 0); /* just in case :-) */ | ||
2150 | add234(tree2, strings[1]); | ||
2151 | add234(tree4, strings[0]); | ||
2152 | array[0] = strings[0]; | ||
2153 | array[1] = strings[1]; | ||
2154 | verifytree(tree, array, 0); | ||
2155 | verifytree(tree2, array+1, 1); | ||
2156 | verifytree(tree3, array, 0); | ||
2157 | verifytree(tree4, array, 1); | ||
2158 | |||
2159 | /* | ||
2160 | * So: | ||
2161 | * - join(tree,tree3) should leave both tree and tree3 unchanged. | ||
2162 | * - joinr(tree,tree2) should leave both tree and tree2 unchanged. | ||
2163 | * - join(tree4,tree3) should leave both tree3 and tree4 unchanged. | ||
2164 | * - join(tree, tree2) should move the element from tree2 to tree. | ||
2165 | * - joinr(tree4, tree3) should move the element from tree4 to tree3. | ||
2166 | * - join(tree,tree3) should return NULL and leave both unchanged. | ||
2167 | * - join(tree3,tree) should work and create a bigger tree in tree3. | ||
2168 | */ | ||
2169 | assert(tree == join234(tree, tree3)); | ||
2170 | verifytree(tree, array, 0); | ||
2171 | verifytree(tree3, array, 0); | ||
2172 | assert(tree2 == join234r(tree, tree2)); | ||
2173 | verifytree(tree, array, 0); | ||
2174 | verifytree(tree2, array+1, 1); | ||
2175 | assert(tree4 == join234(tree4, tree3)); | ||
2176 | verifytree(tree3, array, 0); | ||
2177 | verifytree(tree4, array, 1); | ||
2178 | assert(tree == join234(tree, tree2)); | ||
2179 | verifytree(tree, array+1, 1); | ||
2180 | verifytree(tree2, array, 0); | ||
2181 | assert(tree3 == join234r(tree4, tree3)); | ||
2182 | verifytree(tree3, array, 1); | ||
2183 | verifytree(tree4, array, 0); | ||
2184 | assert(NULL == join234(tree, tree3)); | ||
2185 | verifytree(tree, array+1, 1); | ||
2186 | verifytree(tree3, array, 1); | ||
2187 | assert(tree3 == join234(tree3, tree)); | ||
2188 | verifytree(tree3, array, 2); | ||
2189 | verifytree(tree, array, 0); | ||
2190 | |||
2191 | return 0; | ||
2192 | } | ||
2193 | |||
2194 | #endif | ||
2195 | |||
2196 | #if 0 /* sorted list of strings might be useful */ | ||
2197 | { | ||
2198 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", | ||
2199 | } | ||
2200 | #endif | ||