chiark / gitweb /
CMakeLists.txt, lib.h, t/soak, t/treetest.c: Add some support for Windows.
[xyla] / bt.h
1 /* -*-c-*-
2  *
3  * Basic binary tree operations
4  *
5  * (c) 2024 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Xyla, a library of binary trees.
11  *
12  * Xyla is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Lesser General Public License as published by the
14  * Free Software Foundation; either version 3 of the License, or (at your
15  * option) any later version.
16  *
17  * Xyla is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with Xyla.  If not, see <https://www.gnu.org/licenses/>.
24  */
25
26 #ifndef XYLA_BT_H
27 #define XYLA_BT_H
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include <limits.h>
32 #include <stddef.h>
33
34 #ifndef XYLA_FREESTANDING
35 #  include <stdio.h>
36 #  include <string.h>
37 #  ifndef XYLA__ASSERT
38 #    include <assert.h>
39 #    define XYLA__ASSERT assert
40 #  endif
41 #else
42 #  ifndef XYLA__ASSERT
43 #    define XYLA__ASSERT(x) do (void)(x); while (0)
44 #  endif
45 #endif
46
47 /*----- Data structures ---------------------------------------------------*/
48
49 #define XYLA_RC_DOLOSE(_)                                               \
50   /* add new error codes at the top here */                             \
51   _(NOMEM,      "out of memory")                                        \
52   _(BAD,        "tree structure invalid")                               \
53   _(TALL,       "height limit exceeded")                                \
54   _(FAIL,       "operation failed")
55 #define XYLA_RC_DOWIN(_)                                                \
56   _(OK,         "ok")                                                   \
57   _(HTCHG,      "height changed")                                       \
58   /* add new success codes at the bottom here */
59
60 enum {
61 #define XYLA__RC_DEFLOSE(tag, msg) XYLA__RCLOSE_##tag,
62   XYLA_RC_DOLOSE(XYLA__RC_DEFLOSE)
63 #undef XYLA__RC_DEFLOSE
64   XYLA__RCLOSE_LIMIT
65 };
66
67 enum {
68 #define XYLA__RC_DEFWIN(tag, msg) XYLA_RC_##tag,
69   XYLA_RC_DOWIN(XYLA__RC_DEFWIN)
70 #undef XYLA__RC_DEFWIN
71   XYLA_RC_WINLIMIT,
72
73 #define XYLA__RC_DEFLOSE(tag, msg) XYLA_RC_##tag =                      \
74         -XYLA__RCLOSE_LIMIT + XYLA__RCLOSE_##tag,
75   XYLA_RC_DOLOSE(XYLA__RC_DEFLOSE)
76 #undef XYLA__RC_DEFLOSE
77   XYLA_RC_LOSELIMIT = -XYLA__RCLOSE_LIMIT,
78 };
79
80 struct xyla_bt_node {
81   /* The intrusion into a binary tree node. */
82
83   struct xyla_bt_node *left, *right;   /* links to left and right subtrees */
84 };
85 #define XYLA_BT_NODEPFX struct xyla_bt_node bt
86 #define XYLA_BT_NODEUSFX struct xyla_bt_node bt
87
88 struct xyla_bt_nodecls {
89   /* Tree node class. */
90
91   const struct xyla_bt_nodeops *ops;    /* pointer to node operations */
92 };
93
94 enum {
95   /* Node position code. */
96
97   XYLA_BTPOS_ROOT,                      /* node is the root */
98   XYLA_BTPOS_LEFT,                      /* node is a left child */
99   XYLA_BTPOS_RIGHT                      /* node is a right child */
100 };
101
102 typedef void xyla_bt_updfn(struct xyla_bt_nodecls */*cls*/,
103                            struct xyla_bt_node */*node*/);
104   /* Node update function.  Called when a node's child pointers are modified,
105    * to recompute summary data.
106    */
107
108 typedef void xyla__dummyfn(void);
109   /* A dummy function, currently unused.  Must be null for forwards
110    * compatibility.
111    */
112
113 struct xyla_bt_nodeops {
114   /* Node operations table. */
115
116   size_t sz;
117   xyla_bt_updfn *upd;
118   xyla__dummyfn *_rsvd2, *_rsvd3;
119 };
120 #define XYLA_BT_NODEOPSPFX struct xyla_bt_nodeops node
121 #define XYLA_BT_NODEOPSUSFX struct xyla_bt_nodeops node
122
123 typedef int xyla_bt_navfn(struct xyla_bt_nodecls */*cls*/,
124                           const struct xyla_bt_node */*node*/,
125                           void */*arg*/);
126   /* Navigation function, called from `lookup', `probe' and related
127    * functions.  Passed a NODE pointer and an opaque pointer ARG from the
128    * caller.  Return zero if the NODE is the one sought; negative to
129    * continue the search into NODE's left subtree; or positive to continue
130    * the search into NODE's right subtree.
131    */
132
133 typedef const void *xyla_bt_keyfn(struct xyla_bt_nodecls */*cls*/,
134                                   const struct xyla_bt_node */*node*/);
135   /* Key projection function, called from set operations.  Return a pointer
136    * to the NODE's key data, suitable for passing to the corresponding
137    * navigation function.
138    */
139
140 struct xyla_bt_ordopslots {
141   /* Ordering operations table. */
142
143   xyla_bt_navfn *nav;
144   xyla_bt_keyfn *key;
145 };
146 #define XYLA_BT_ORDOPSPFX XYLA_BT_NODEOPSPFX; struct xyla_bt_ordopslots ord
147 struct xyla_bt_ordops { XYLA_BT_ORDOPSPFX; };
148 #define XYLA_BT_ORDOPSUSFX struct xyla_bt_ordops ord; XYLA_BT_NODEOPSUSFX
149 union xyla_bt_ordopsu { XYLA_BT_ORDOPSUSFX; };
150
151 typedef int xyla_bt_ascendfn(struct xyla_bt_node */*node*/,
152                              struct xyla_bt_node */*parent*/,
153                              struct xyla_bt_node */*sibling*/,
154                              unsigned /*pos*/, void */*arg*/);
155   /* Ascension function; see `XYLA_BT_ASCEND'.  Called on a NODE, together
156    * with its PARENT, SIBLING, and POS (`XYLA_POS_...') indicating the
157    * node's position relative to its parent; ARG is an opaque pointer
158    * provided by the caller, usually a pointer to some structure which is
159    * updated by the ascension function.
160    */
161
162 /*----- Diagnostics -------------------------------------------------------*/
163
164 extern const char *xyla_strerror(int /*rc*/);
165   /* Return the message string associated with the return code RC. */
166
167 /*----- Iteration ---------------------------------------------------------*/
168
169 /* Background on iteration.
170  *
171  * Consider an arbitrary node N in a binary tree.  The next nodes to visit
172  * are those in N's right subtree.  Then, if N is a left child, we must visit
173  * N's parent, followed by the subtree headed by N's sibling.
174  *
175  * The invariant that we maintain is as follows.
176  *
177  *   * If the stack is empty, then all nodes have been visited.
178  *
179  *   * If the stack is nonempty, then the topmost entry in the stack is the
180  *     least node which has not yet been visited -- and therefore is the next
181  *     node to visit.
182  *
183  *     The lower entries in the stack are, in top-to-bottom order, those of
184  *     the topmost stack node's ancestors, from parent to root, which have
185  *     not yet been visited.  In other words, a node appears in the stack if
186  *     and only if some node in its left subtree is nearer to the top of the
187  *     stack.
188  *
189  * The stack is initialized by pushing the root, the root's left child, its
190  * leftmost grandchild, and so on.  This establishes the invariants above:
191  * the leftmost leaf is the first node to be visited, and its entire ancestry
192  * is on the stack since none of these nodes has yet been visited.  If the
193  * tree is empty, the root is null, so we have done nothing and left the
194  * stack empty.
195  *
196  * When we come to actually visit a node, we pop the topmost node from the
197  * stack.  We don't return it yet: we must restore the invariant.
198  *
199  *   * If the node to visit has a right subtree, then the next node to visit
200  *     is the leftmost node in that subtree.  All of the nodes on the stack
201  *     are unvisited ancestors of the current node, and therefore of every
202  *     node in its right subtree.  We're just about to visit the current
203  *     node, so that should indeed indeed have been removed.  The right
204  *     subtree contains descendants of the current node, so they are not yet
205  *     on the stack, but they have not yet been visited.  We therefore push
206  *     the current node's right child, its left child, leftmost grandchild,
207  *     and so on.
208  *
209  *   * Otherwise, we have just finished traversing a subtree.  Either we are
210  *     now done, or we have just finished traversing the left subtree of the
211  *     enxt topmost node on the stack.  This must therefore be the next node
212  *     to visit, and the remainder of the stack is already correct.
213  */
214
215 #define XYLA_BT_STEPITER(rc, node, stack, sp, max, back) do {           \
216   /* Advance the tree iterator represented by STACK and SP; the stack   \
217    * contains space for at least MAX elements.  A new left-to-right     \
218    * iterator can be initialized by passing NODE as the tree root,      \
219    * SP = 0, and BACK = `left'.  Once the iterator is set up:           \
220    *                                                                    \
221    *   * if SP is zero, there are no more nodes;                        \
222    *                                                                    \
223    *   * otherwise, the next NODE in order is STACK[--SP]; call again,  \
224    *     passing NODE->right to update the stack.                       \
225    *                                                                    \
226    * Similarly, to iterate right-to-left, pass BACK = `right' and pass  \
227    * NODE->left to update.                                              \
228    *                                                                    \
229    * If RC is `XYLA_RC_TALL' on exit, then the stack was too small for  \
230    * the tree height: to make progress, either the stack must be        \
231    * extended or the tree must be rebalanced to limit its height.  On   \
232    * failure, stack entries beyond the initial stack pointer may be     \
233    * clobbered, but entries below the stack pointer, and the stack      \
234    * pointer itself, are preserved.  If you extend the stack vector,    \
235    * you can either just retry, or, more efficiently, advance the stack \
236    * pointer to MAX and call with NODE = STACK[MAX - 1]->left.          \
237    */                                                                   \
238                                                                         \
239   const struct xyla_bt_node *_node = (node), **_stack = (stack);        \
240   int _sp = (sp), _max = (max);                                         \
241                                                                         \
242   for (;;)                                                              \
243     if (!_node) { (sp) = _sp; (rc) = XYLA_RC_OK; break; }               \
244     else if (_sp >= _max) { (rc) = XYLA_RC_TALL; break; }               \
245     else { _stack[_sp++] = _node; _node = _node->back; }                \
246 } while (0)
247
248 extern void *xyla_bt_severfirst(struct xyla_bt_node **/*root*/);
249   /* Remove and return the first node in the traversal order of the tree
250    * rooted at *ROOT.  The tree is restructured in a simple way which likely
251    * invalidates any invariants maintained by the application or balance
252    * policy, so this is mostly useful if the entire tree is about to be
253    * destroyed.
254    */
255
256 /*----- Paths -------------------------------------------------------------*/
257
258 /* Background on paths.
259  *
260  * The structure describes a path from the root to a node, or to a null link
261  * denoting a place to insert a node, by indicating the links that are
262  * followed.  A path which ends with a link to a node is a `full' path, while
263  * one that ends with a null link is an `empty' path.
264  *
265  * The first link followed is always the root link in the tree header, so
266  * PATH[0] is always the address of the tree root link.  After that, each
267  * step involves following a left or right pointer from a node to one of its
268  * children, so, for 0 <= i < k, we have
269  *
270  *   PATH[i + 1] == &(*PATH[i])->left || PATH[i + 1] == &(*PATH[i])->right .
271  *
272  * For reasons of internal convenience, K is not the length of the path, but
273  * one less than this, so *PATH[K] is the node or null link which terminates
274  * the path.
275  */
276
277 #define XYLA_BT_CURRENT(path, k) (*(path)[(k)])
278   /* Return the node currently designated by the PATH, or null if the path is
279    * empty.
280    */
281
282 #ifdef XYLA_FREESTANDING
283 #  define XYLA_BT_COPYPATH(newpath, path, k) do {                       \
284      struct xyla_bt_node                                                \
285        ***_newpath = (newpath),                                         \
286        **const *_path = (path);                                         \
287      int _i, _n = (k) + 1;                                              \
288                                                                         \
289      for (_i = 0; _i < _n; _i++) _newpath[_i] = _path[_i];              \
290    } while (0)
291 #else
292 #  define XYLA_BT_COPYPATH(newpath, path, k) do {                       \
293      memcpy((newpath), (path),                                          \
294             ((k) + 1)*sizeof(struct xyla_bt_node **));                  \
295    } while (0)
296 #endif
297   /* Copy the (K + 1) path entries from PATH to NEWPATH. */
298
299 #define XYLA_BT_EXTRMPATH(rc, node, root, path, k, dir, htmax) do {     \
300   /* Set NODE to be the first (if DIR is `left') or last (if DIR is     \
301    * `right') node in the tree whose root link is at ROOT, with a path  \
302    * to the requested node, which can be used to remove it, or to       \
303    * navigate to other nodes in the tree, stored in PATH, with its      \
304    * length left in K.  If the tree is empty, set NODE to be null.      \
305    *                                                                    \
306    * If the path length to the chosen node exceeds HTMAX then set       \
307    * RC = `XYLA_RC_TALL'; otherwise, RC = `XYLA_RC_OK' on exit.         \
308    */                                                                   \
309                                                                         \
310   struct xyla_bt_node *_node, *_next,                                   \
311     **_root = (root), ***_path = (path);                                \
312   int _k, _htmax = (htmax);                                             \
313                                                                         \
314   /* A path always begins with the root link. */                        \
315   _k = 0; _path[0] = _root; _node = *_root;                             \
316                                                                         \
317   if (!_node) {                                                         \
318     /* The tree is empty.  The path is empty and covers only the root   \
319      * link.                                                            \
320      */                                                                 \
321                                                                         \
322     (node) = 0; (k) = _k; (rc) = XYLA_RC_OK;                            \
323   } else {                                                              \
324     /* There is at least one node.  We trace out a full path to one end \
325      * of the tree.  There's a slight inconsistency here because the    \
326      * root link will be present regardless of whether the path is full \
327      * or empty.                                                        \
328      */                                                                 \
329                                                                         \
330     for (;;) {                                                          \
331       _next = _node->dir;                                               \
332       if (!_next)                                                       \
333         { (node) = _node; (k) = _k; (rc) = XYLA_RC_OK; break; }         \
334       else if (_k >= _htmax)                                            \
335         { (rc) = XYLA_RC_TALL; (node) = 0; break; }                     \
336       else                                                              \
337         { _path[++_k] = &_node->dir; _node = _next; }                   \
338     }                                                                   \
339   }                                                                     \
340 } while (0)
341
342 #define XYLA_BT_STEPPATH(rc, node, path, k, dir, opp, htmax) do {       \
343   /* Set NODE to be the next (if DIR is `right' and OPP is `left') or   \
344    * previous (if DIR is `left' and OPP is `right') node in the tree,   \
345    * relative to the current PATH position, updating the path to the    \
346    * requested node.  The path may be either full, in which case the    \
347    * macro finds the current node's successor or predecessor, or empty, \
348    * in which case it finds the nearest node before or after the gap to \
349    * which the path refers.  If the path already refers to the last or  \
350    * first node, or to the gap beyond, then set `node' to a null        \
351    * pointer and adjust PATH to refer to the appropriate extreme null   \
352    * link.                                                              \
353    *                                                                    \
354    * If the path length to the chosen node exceeds HTMAX then set       \
355    * RC = `XYLA_RC_TALL' without altering the path; otherwise, set      \
356    * RC = `XYLA_RC_OK' on exit.                                         \
357    */                                                                   \
358                                                                         \
359   struct xyla_bt_node *_node0, *_node, *_next,                          \
360     **_link, **_plink, ***_path = (path);                               \
361   int _k0 = (k), _k = _k0, _htmax = (htmax);                            \
362                                                                         \
363   /* Collect the start node and the link address. */                    \
364   _link = _path[_k]; _node0 = *_link;                                   \
365                                                                         \
366   /* If there's a node, then we should explore the subtree on the       \
367    * relevant side if there is one.                                     \
368    */                                                                   \
369   if (_node0) {                                                         \
370     _next = _node0->dir;                                                \
371     if (_next) {                                                        \
372       /* There is indeed a subtree on the relevant side.  We need to    \
373        * chase links in the opposite direction to find the next node.   \
374        */                                                               \
375                                                                         \
376       if (_k >= _htmax)                                                 \
377         { (rc) = XYLA_RC_TALL; (node) = 0; }                            \
378       else {                                                            \
379         _path[++_k] = &_node0->dir; _node = _next;                      \
380         for (;;) {                                                      \
381           _next = _node->opp;                                           \
382           if (!_next)                                                   \
383             { (node) = _node; (k) = _k; (rc) = 0; break; }              \
384           else if (_k >= _htmax)                                        \
385             { (rc) = XYLA_RC_TALL; (node) = 0; break; }                 \
386           else                                                          \
387             { _path[++_k] = &_node->opp; _node = _next; }               \
388         }                                                               \
389       }                                                                 \
390       break;                                                            \
391     }                                                                   \
392   }                                                                     \
393                                                                         \
394   /* There either isn't a node at all, or its subtree on the relevant   \
395    * side is empty.  Ascend the tree, searching for the most recent     \
396    * ancestor in the required direction.                                \
397    */                                                                   \
398   for (;;) {                                                            \
399                                                                         \
400     /* If there's no more tree to ascend then set the path to refer to  \
401      * a terminating null link beyond the initial node.  We know that   \
402      * either the initial path was empty, in which case it's already    \
403      * good, or its subtree was empty, in which case we select that.    \
404      * Note that we don't modify the path before this point so it's     \
405      * safe to revert the path length here.                             \
406      */                                                                 \
407     if (!_k) {                                                          \
408       _k = _k0;                                                         \
409       if (!_node0)                                                      \
410         { (node) = 0; /* `k' already correct */ (rc) = XYLA_RC_OK; }    \
411       else if (_k >= _htmax)                                            \
412         { (rc) = XYLA_RC_TALL; (node) = 0; }                            \
413       else {                                                            \
414         _path[++_k] = &_node0->dir;                                     \
415         (node) = 0; (k) = _k; (rc) = XYLA_RC_OK;                        \
416       }                                                                 \
417       break;                                                            \
418     }                                                                   \
419                                                                         \
420     /* Ascend the tree and check the link direction. */                 \
421     _plink = _path[--_k]; _node = *_plink;                              \
422     if (_link == &_node->opp)                                           \
423       { (node) = _node; (k) = _k; (rc) = XYLA_RC_OK; break; }           \
424     _link = _plink;                                                     \
425   }                                                                     \
426 } while (0)
427
428 #define XYLA_BT_NUDGEPATH(rc, path, k, dir, opp, htmax) do {            \
429   /* The PATH must be full, i.e., refer to a node in the tree.  Adjust  \
430    * the path so as to refer instead to the gap immediately before (if  \
431    * DIR is `left' and OPP is `right') or after (if DIR is `right' and  \
432    * OPP is `left') the selected node, suitable to insert an element or \
433    * split the tree just before or after the previously selected node.  \
434    * A call to `XYLA_BT_STEPPATH' in the opposite direction will find   \
435    * the original node again; stepping in the same direction will find  \
436    * the node's predecessor or successor if there is one.               \
437    *                                                                    \
438    * If the path length to the null link exceeds HTMAX then set         \
439    * RC = `XYLA_RC_TALL' without altering the path; otherwise, set      \
440    * RC = `XYLA_RC_OK' on exit.                                         \
441    */                                                                   \
442                                                                         \
443   struct xyla_bt_node *_node, ***_path = (path);                        \
444   int _k = (k), _htmax = (htmax);                                       \
445                                                                         \
446   /* Collect the starting point, and check that the path is full. */    \
447   _node = *_path[_k]; XYLA__ASSERT(_node);                              \
448                                                                         \
449   /* Descend into the appropriate side subtree to find a null link. */  \
450   if (_k >= _htmax)                                                     \
451     (rc) = XYLA_RC_TALL;                                                \
452   else {                                                                \
453     _path[++_k] = &_node->dir; _node = _node->dir;                      \
454     for (;;)                                                            \
455       if (!_node) { (k) = _k; (rc) = XYLA_RC_OK; break; }               \
456       else if (_k >= _htmax) { (rc) = XYLA_RC_TALL; break; }            \
457       else { _path[++_k] = &_node->opp; _node = _node->opp; }           \
458   }                                                                     \
459 } while (0)
460
461 #define XYLA_BT_ROOTPATH(node, root, path, k) do {                      \
462   /* Initialize PATH and K to refer to the tree root, given the address \
463    * ROOT of the root link, and set NODE to be the root node.  The      \
464    * resulting path will be empty if and only if the tree is empty.     \
465    */                                                                   \
466                                                                         \
467   (k) = 0;                                                              \
468   (node) = *((path)[0] = (root));                                       \
469 } while (0)
470
471 #define XYLA_BT_PARENTPATH(node, pos, path, k) do {                     \
472   /* Update the PATH and K to refer to the parent of the link currently \
473    * designated; set NODE to be this parent, and POS to the             \
474    * `XYLA_BTPOS_...'  constant describing the link's relation to the   \
475    * parent.  If the path initially designated the tree's root link,    \
476    * then set NODE to null and POS to `XYLA_BTPOS_ROOT', and leave the  \
477    * path unchanged; otherwise, the tree becomes full, and decrement K  \
478    * by one.                                                            \
479    */                                                                   \
480                                                                         \
481   struct xyla_bt_node **_link, *_node, ***_path = (path);               \
482   int _k = (k);                                                         \
483                                                                         \
484   if (!_k)                                                              \
485     { (node) = 0; (pos) = XYLA_BTPOS_ROOT; }                            \
486   else {                                                                \
487     _link = _path[_k]; (node) = _node = *_path[--_k]; (k) = _k;         \
488     (pos) = _link == &_node->left ?                                     \
489               XYLA_BTPOS_LEFT : XYLA_BTPOS_RIGHT;                       \
490   }                                                                     \
491 } while (0)
492
493 #define XYLA_BT_CHILDPATH(rc, node, path, k, dir, htmax) do {           \
494   /* Update the PATH and K to refer to the left (if DIR is `left') or   \
495    * right (if DIR is `right') child of the node currently designated,  \
496    * and set NODE to be this child node.  The path must initially have  \
497    * been full, and may become empty as a result.                       \
498    *                                                                    \
499    * If the path length to the chosen node exceeds HTMAX then set       \
500    * RC = `XYLA_RC_TALL' without altering the path; otherwise, set      \
501    * RC = `XYLA_RC_OK' on exit.                                         \
502    */                                                                   \
503                                                                         \
504   struct xyla_bt_node *_node, ***_path = (path);                        \
505   int _k = (k), _htmax = (htmax);                                       \
506                                                                         \
507   _node = *_path[_k]; XYLA__ASSERT(_node);                              \
508   if (_k >= _htmax)                                                     \
509     { (rc) = XYLA_RC_TALL; (node) = 0; }                                \
510   else {                                                                \
511     _path[++_k] = &_node->dir; (k) = _k;                                \
512     (node) = _node->dir; (rc) = XYLA_RC_OK;                             \
513   }                                                                     \
514 } while (0)
515
516 #define XYLA_BT_RIPPLE(cls, path, k) do {                               \
517   /* Update a node's ancestors -- i.e., call the node class `upd'       \
518    * function on them, in ascending order -- after it has been          \
519    * modified.  The PATH and K describe a full path to the node that    \
520    * has been changed.  The PATH remains valid.                         \
521    */                                                                   \
522                                                                         \
523   struct xyla_bt_nodecls *_cls = (cls);                                 \
524   xyla_bt_updfn *_updfn = _cls->ops->upd;                               \
525   struct xyla_bt_node **const *_path = (path);                          \
526   int _k = (k);                                                         \
527                                                                         \
528   XYLA__ASSERT(*_path[_k]); while (_k) _updfn(_cls, *_path[--_k]);      \
529 } while (0)
530
531 #define XYLA_BT_ASCEND(rc, fn, path, k, arg) do {                       \
532   /* Ascend the tree along the PATH, allowing FN to accumulate summary  \
533    * data from the nodes to the root.  For each NODE link on the PATH,  \
534    * including the null link in the case of an empty path, call the FN, \
535    * passing the NODE pointer, its position POS, its PARENT and SIBLING \
536    * pointers, and ARG.  The PATH remains valid.  If the NODE is at the \
537    * root, then POS is `XYLA_BTPOS_ROOT', and PARENT and SIBLING are    \
538    * null; otherwise, POS is `XYLA_BTPOS_LEFT' or `XYLA_BTPOS_RIGHT',   \
539    * PARENT is the node's parent, and SIBLING points to the node's      \
540    * sibling if any.  If FN returns nonzero, then stop immediately,     \
541    * setting RC to the nonzero return value; otherwise, set RC to zero  \
542    * on exit.                                                           \
543    */                                                                   \
544                                                                         \
545   xyla_bt_ascendfn *_fn = (fn);                                         \
546   struct xyla_bt_node *_node, **_nlink, *_parent, **_plink,             \
547     **const *_path = (path);                                            \
548   int _k = (k), _rc;                                                    \
549   void *_arg = (arg);                                                   \
550                                                                         \
551   _nlink = _path[_k]; _node = *_nlink;                                  \
552   for (;;) {                                                            \
553     if (!_k) { (rc) = _fn(_node, 0, 0, XYLA_BTPOS_ROOT, _arg); break; } \
554     _plink = _path[--_k]; _parent = *_plink;                            \
555     if (_nlink == &_parent->left)                                       \
556       _rc = _fn(_node, _parent, _parent->right, XYLA_BTPOS_LEFT, _arg); \
557     else                                                                \
558       _rc = _fn(_node, _parent, _parent->left, XYLA_BTPOS_RIGHT, _arg); \
559     if (_rc) { (rc) = _rc; break; }                                     \
560     _nlink = _plink; _node = _parent;                                   \
561   }                                                                     \
562 } while (0)
563
564 /*----- Searching ---------------------------------------------------------*/
565
566 #define XYLA_BT_LOOKUP(node, cls, root, navfn, arg) do {                \
567   /* Search for a node within the tree rooted at ROOT.  The search is   \
568    * guided by NAVFN, passing it ARG at each node.  If the function     \
569    * matches a node, then set NODE to the matching node; otherwise NODE \
570    * is null on exit.                                                   \
571    */                                                                   \
572                                                                         \
573   struct xyla_bt_node *_node;                                           \
574   struct xyla_bt_nodecls *_cls = (cls);                                 \
575   const struct xyla_bt_ordops *_ops;                                    \
576   xyla_bt_navfn *_navfn = (navfn);                                      \
577   void *_arg = (arg);                                                   \
578   int _dir;                                                             \
579                                                                         \
580   /* If no NAVFN is provided, then see if there's one in the node       \
581    * class.                                                             \
582    */                                                                   \
583   if (!_navfn) {                                                        \
584     _ops = (const struct xyla_bt_ordops *)_cls->ops;                    \
585     _navfn = _ops->ord.nav;                                             \
586   }                                                                     \
587                                                                         \
588   /* Unsurprisingly, start at the root. */                              \
589   _node = (root);                                                       \
590                                                                         \
591   /* Descend the tree. */                                               \
592   for (;;) {                                                            \
593                                                                         \
594     /* If we've reached the end, then give up. */                       \
595     if (!_node) { (node) = 0; break; }                                  \
596                                                                         \
597     /* Consult the navigation function to decide where to go next. */   \
598     _dir = _navfn(_cls, _node, _arg);                                   \
599     if (_dir < 0) _node = _node->left;                                  \
600     else if (_dir > 0) _node = _node->right;                            \
601     else { (node) = _node; break; }                                     \
602   }                                                                     \
603 } while (0)
604
605 #define XYLA_BT_PROBE(rc, node, cls, root, navfn, arg,                  \
606                       path, k, htmax) do {                              \
607   /* Search for a node within the tree according to NAVFN, recording    \
608    * the search path.                                                   \
609    *                                                                    \
610    * If the path length to the chosen node or link exceeds HTMAX then   \
611    * set RC = `XYLA_RC_TALL' without altering the path; otherwise, set  \
612    * RC = `XYLA_RC_OK' on exit.                                         \
613    *                                                                    \
614    * Balanced tree structures which maintain a constant bound on the    \
615    * maximum possible height of a tree never experience failure.  Less  \
616    * carefully-maintained trees must check for and handle failure: a    \
617    * usual response would be to rebalance the tree and try again; a     \
618    * second failure should be impossible.  Note that `failure' to find  \
619    * a matching node is still considered success for the purposes of    \
620    * the return value.                                                  \
621    */                                                                   \
622                                                                         \
623   struct xyla_bt_node *_node, **_link,                                  \
624     **_root = (root), ***_path = (path);                                \
625   struct xyla_bt_nodecls *_cls = (cls);                                 \
626   const struct xyla_bt_ordops *_ops;                                    \
627   xyla_bt_navfn *_navfn = (navfn);                                      \
628   void *_arg = (arg);                                                   \
629   int _k, _htmax = (htmax), _dir;                                       \
630                                                                         \
631   /* If no NAVFN is provided, then see if there's one in the node       \
632    * class.                                                             \
633    */                                                                   \
634   if (!_navfn) {                                                        \
635     _ops = (const struct xyla_bt_ordops *)_cls->ops;                    \
636     _navfn = _ops->ord.nav;                                             \
637   }                                                                     \
638                                                                         \
639   /* Unsurprisingly, start at the root. */                              \
640   _path[0] = _root; _k = 0; _node = *_root;                             \
641                                                                         \
642   /* Descend the tree. */                                               \
643   for (;;) {                                                            \
644                                                                         \
645     /* If we've reached the end, then give up. */                       \
646     if (!_node) { (node) = 0; (k) = _k; (rc) = XYLA_RC_OK; break; }     \
647                                                                         \
648     /* Consult the navigation function to decide where to go next. */   \
649     _dir = _navfn(_cls, _node, _arg);                                   \
650     if (_dir < 0) _link = &_node->left;                                 \
651     else if (_dir > 0) _link = &_node->right;                           \
652     else { (node) = _node; (k) = _k; (rc) = XYLA_RC_OK; break; }        \
653                                                                         \
654     /* Append the link to the path and continue. */                     \
655     if (_k >= _htmax) { (rc) = XYLA_RC_TALL; (node) = 0; break; }       \
656     _path[++_k] = _link; _node = *_link;                                \
657   }                                                                     \
658 } while (0)
659
660 /*----- Removal -----------------------------------------------------------*/
661
662 extern int xyla_bt_remove(struct xyla_bt_node **/*del_out*/,
663                           struct xyla_bt_node **/*subst_out*/,
664                           struct xyla_bt_node **/*replace_out*/,
665                           struct xyla_bt_node ***/*path*/, int */*k_inout*/,
666                           int /*htmax*/);
667   /* Remove a node from a binary tree.
668    *
669    * The (*K_INOUT + 1)-step PATH must be full, i.e., its final link must
670    * point to a node present in the tree.  It's that node which is to be
671    * removed; a pointer to it is stored in *DEL_OUT.
672    *
673    * If the deleted node has two children, then it can't easily be
674    * disentangled from the tree.  Instead, the node is swapped with its
675    * immediate successor, which must exist because the node has two children
676    * and therefore a right child.  On the other hand, the immediate successor
677    * is the leftmost node in the deleted node's right subtree, and therefore
678    * has no left child.  In this case, *SUBST_NODE is set to the successor
679    * node, which may require some further fixing up (e.g., to maintain
680    * balance state).  The path is extended, by appending addition link
681    * pointers and updating *K_INOUT, to refer to the place at which the
682    * successor node was linked.  If the deleted node doesn't have both
683    * children, none of this is necessary: *SUBST_NODE is set to null, and the
684    * path is left unchanged.  If there is insufficient space in the path
685    * vector, then return `XYLA_RC_TALL'.
686    *
687    * The node (after substitution) is replaced with its child, if it has one,
688    * or a null pointer.  This replacement node is returned in *REPLACE_OUT.
689    *
690    * The modified nodes are all on the PATH; updating them is left for the
691    * caller.
692    *
693    * Return `XYLA_RC_OK' on success.
694    */
695
696 /*----- Set operations ----------------------------------------------------*/
697
698 typedef int xyla_bt_joinfn(struct xyla_bt_nodecls */*cls*/,
699                            struct xyla_bt_node **/*root_out*/,
700                              int */*rootht_out*/,
701                            struct xyla_bt_node **/*left*/, int /*lht*/,
702                            struct xyla_bt_node */*mid*/,
703                            struct xyla_bt_node **/*right*/, int /*rht*/);
704   /* Join two trees rooted at *LEFT and *RIGHT, with heights LHT and RHT,
705    * with the separating node MID (which may be null to join the trees with
706    * no additional separator).  Write the root of the joined tree to
707    * *ROOT_OUT and its height (if interesting) to *ROOTHT_OUT.  Return a
708    * `XYLA_RC_...' code, but failure is not currently permitted.
709    */
710
711 typedef int xyla_bt_splitatfn(struct xyla_bt_nodecls */*cls*/,
712                               struct xyla_bt_node **/*left_out*/,
713                                 int */*lht_out*/,
714                               struct xyla_bt_node **/*mid_out*/,
715                               struct xyla_bt_node **/*right_out*/,
716                                 int */*rht_out*/,
717                               struct xyla_bt_node **/*root*/,
718                               const void */*key*/);
719   /* Split the tree rooted at *ROOT at the position indicated by the KEY.
720    * Write the roots of the resulting left and right trees to *LEFT_OUT and
721    * *RIGHT_OUT, and their heights, if interesting, to *LHT_OUT and *RHT_OUT.
722    * If a node matching KEY was found, then it is not included in either
723    * subtree: instead, a store a pointer to the matching node in *MID_OUT;
724    * otherwise, set *MID_OUT to null.  Return a `XYLA_RC_...' code, but
725    * failure is not currently permitted.
726    */
727
728 typedef int xyla_bt_splitrootfn(struct xyla_bt_node **/*left_out*/,
729                                   int */*lht_out*/,
730                                 struct xyla_bt_node **/*root_out*/,
731                                 struct xyla_bt_node **/*right_out*/,
732                                   int */*rht*/,
733                                 struct xyla_bt_node **/*root*/,
734                                   int /*treeht*/);
735   /* Split the tree rooted at *ROOT, with height TREEHT, at its root.  Write
736    * the roots of the left and right subtrees to *LEFT_OUT and *RIGHT_OUT,
737    * and their heights, if interesting, to *LHT_OUT and *RHT_OUT, and the
738    * original root node to *ROOT_OUT.  Return a `XYLA_RC_...' code, but
739    * failure is not currently permitted.
740    */
741
742 struct xyla_bt_treeops {
743   /* Tree operations table. */
744
745   xyla_bt_joinfn *join;
746   xyla_bt_splitatfn *splitat;
747   xyla_bt_splitrootfn *splitroot;
748 };
749
750 struct xyla_bt_setopstack {
751   /* Stack entries for set operations. */
752
753   unsigned op;
754   union {
755     struct {
756       struct xyla_bt_node *a; int aht;
757       struct xyla_bt_node *b; int bht;
758     } right;
759     struct {
760       struct xyla_bt_node *uni; int uniht;
761       struct xyla_bt_node *isect; int isectht;
762     } join_union;
763     struct {
764       struct xyla_bt_node *diff; int diffht;
765       struct xyla_bt_node *isect; int isectht;
766     } join_diff;
767   } u;
768   struct xyla_bt_node *am, *bm;
769 };
770
771 extern int xyla_bt_unisect(struct xyla_bt_nodecls */*cls*/,
772                            struct xyla_bt_node **/*uni_out*/,
773                              int */*uniht_out*/,
774                            struct xyla_bt_node **/*isect_out*/,
775                              int */*isectht_out*/,
776                            struct xyla_bt_node **/*aroot*/,
777                              int */*aht_inout*/,
778                            struct xyla_bt_node **/*broot*/,
779                              int */*bht_inout*/,
780                            const struct xyla_bt_treeops */*ops*/,
781                            struct xyla_bt_setopstack */*stack*/,
782                            int /*htmax*/);
783   /* Compute the union and intersection of two trees.
784    *
785    * On entry, *AROOT and *BROOT are the roots of two trees a and b, with
786    * their respective heights in *AHT_INOUT and *BHT_INOUT.  The trees are
787    * considered to represent sets, with one element per node; the element is
788    * determined by the `key' node-class operation.  On exit, *UNI_OUT points
789    * to the root of a tree containing (one copy of) each element present in
790    * either a or b, and *ISECT_OUT points to the root of a tree containing
791    * the other copy of each element present in both a and b; the heights of
792    * the output trees (the exact meaning of which is determined by the tree
793    * implementation) are stored in *UNIHT_OUT and *ISECTHT_OUT.  If AROOT
794    * and/or BROOT are distinct from UNI_OUT and ISECT_OUT, then null pointers
795    * are stored in them.  The original trees are destroyed; each node in the
796    * original operands trees ends up in exactly one of the result trees.
797    *
798    * The STACK argument points to caller-provided workspace, with HTMAX
799    * entries.  The function returns `XYLA_RC_OK' on success.  If the stack is
800    * too small then it returns `XYLA_RC_TALL'; *UNI_OUT and *ISECT_OUT are
801    * unchanged; and the trees rooted at *AROOT and *BROOT are modified, with
802    * their heights at *AHT_INOUT and *BHT_INOUT updated.  Retrying the
803    * operation with a larger stack or following rebalancing will produce the
804    * correct result.  The critical factor is the maximum height of the tree
805    * at *AROOT.
806    */
807
808 extern int xyla_bt_diffsect(struct xyla_bt_nodecls */*cls*/,
809                             struct xyla_bt_node **/*diff_out*/,
810                               int */*diffht_out*/,
811                             struct xyla_bt_node **/*isect_out*/,
812                               int */*isectht_out*/,
813                             struct xyla_bt_node **/*aroot*/,
814                               int */*aht_inout*/,
815                             struct xyla_bt_node **/*broot*/,
816                             const struct xyla_bt_treeops */*ops*/,
817                             struct xyla_bt_setopstack */*stack*/,
818                               int /*htmax*/);
819   /* Compute the set difference of the two operand trees.
820    *
821    * On entry, *AROOT and *BROOT are the roots of two trees a and b, with a's
822    * height in *AHT_INOUT (the height of b is not significant).  The trees
823    * are considered to represent sets, with one element per node; the element
824    * is determined by the `key' node-class operation.  On exit, *DIFF_OUT
825    * points to the root of a tree containing each element of a but not b, and
826    * *ISECT_OUT points to the root of a tree containing each element of a
827    * that's also in b; the heights of the output trees (the exact meaning of
828    * which is determined by the tree implementation) are stored in
829    * *DIFFHT_OUT and *ISECTHT_OUT.  If AROOT and/or BROOT are distinct from
830    * DIFF_OUT and ISECT_OUT, then null pointers are stored in them.  The
831    * original a tree is destroyed; each node in the original operands trees
832    * ends up in exactly one of the result trees.  The input b tree is
833    * unchanged.
834    *
835    * The STACK argument points to caller-provided workspace, with HTMAX
836    * entries.  The function return `XYLA_RC_OK' on success.  If the stack is
837    * too small then it returns `XYLA_RC_TALL'; *DIFF_OUT is unchanged, and
838    * the nodes of the a tree are split between output trees rooted at *AROOT
839    * and *ISECT_OUT, with the heights at *AHT_INOUT and *ISECTHT_OUT set
840    * appropriately.  The critical factor is the maximum height of the tree at
841    * *BROOT.  The correct result can be obtained by (a) restoring the
842    * original a set as the union of the *AROOT and *ISECTHT_OUT trees and (b)
843    * retrying the original difference computation with a rebalanced b tree.
844    * Note that the intersection result from (a) will be empty.
845    */
846
847 /*----- Checking ----------------------------------------------------------*/
848
849 #ifndef XYLA_FREESTANDING
850
851 enum {
852   /* Operation code passed to checking functions. */
853
854   XYLA_CHKOP_NIL,                       /* a null link */
855   XYLA_CHKOP_SETUP,                     /* initialize node information */
856   XYLA_CHKOP_BEFORE,                    /* before the children */
857   XYLA_CHKOP_MID,                       /* after left child, before right */
858   XYLA_CHKOP_AFTER,                     /* after both children */
859   XYLA_CHKOP_TEARDOWN                   /* release node information */
860 };
861
862 struct xyla_bt_check;
863
864 typedef int xyla_bt_chkfn(unsigned /*op*/,
865                           const struct xyla_bt_check */*chk*/);
866   /* A tree checker function.  It's passed an OP code, which is one of the
867    * `XYLA_CHKOP_...' codes listed above, and a pointer CHK to the checking
868    * state.
869    *
870    * The function returns a `XYLA_RC_...' code, which may be `XYLA_RC_OK' if
871    * all is well, `XYLA_RC_BAD' to record that the tree structure is invalid,
872    * or anything else to abort checking.  The `XYLA_CHKOP_TEARDOWN' operation
873    * must not fail.
874    */
875
876 typedef void xyla_bt_idfn(struct xyla_bt_nodecls */*cls*/,
877                           const struct xyla_bt_node */*node*/, FILE */*fp*/);
878   /* Print a description of the NODE to the output stream FP. */
879
880 struct xyla_bt_chkopslots {
881   /* Checking operations table. */
882
883   xyla_bt_chkfn *chk; size_t infosz;
884   xyla_bt_idfn *id;
885 };
886 #define XYLA_BT_CHKOPSPFX XYLA_BT_ORDOPSPFX; struct xyla_bt_chkopslots chk
887 struct xyla_bt_chkops { XYLA_BT_CHKOPSPFX; };
888 #define XYLA_BT_CHKOPSUSFX struct xyla_bt_chkops chk; XYLA_BT_ORDOPSUSFX
889 union xyla_bt_chkopsu { XYLA_BT_CHKOPSUSFX; };
890
891 struct xyla_bt_check {
892   /* Structure holding information passed to checking functions. */
893
894   struct xyla_bt_nodecls *cls;          /* node class */
895   struct xyla_bt_node *const *root;     /* address of root link */
896   FILE *fp;                             /* output file descriptor or null */
897   unsigned f;                           /* flags */
898 #define XYLA_CHKF_COREMASK 0x003fu      /*   flags reserved for core */
899 #define XYLA_CHKF_TREEMASK 0x07c0u      /*   flags reserved for tree */
900 #define XYLA_CHKF_APPMASK 0xf800u       /*   flags reserved for app */
901   const struct xyla_bt_node *parent; void *parent_info; /* parent */
902   const struct xyla_bt_node *node; unsigned pos; void *node_info; /* node */
903   const struct xyla_bt_node *left; void *left_info; /* left child */
904   const struct xyla_bt_node *right; void *right_info; /* right child */
905   void *state;                          /* checker state */
906 };
907
908 extern void xyla_bt_bughdr(const char */*token*/,
909                            struct xyla_bt_node *const */*root*/,
910                            FILE */*fp*/);
911   /* Begin reporting a bug found during checking. */
912
913 extern void xyla_bt_printnode(struct xyla_bt_nodecls */*cls*/,
914                               const struct xyla_bt_node */*node*/,
915                               FILE */*fp*/);
916   /* Print a description of NODE to the stream FP. */
917
918 extern int xyla_bt_check(struct xyla_bt_nodecls */*cls*/,
919                          struct xyla_bt_node *const */*root*/,
920                          FILE */*fp*/, unsigned /*f*/,
921                          xyla_bt_chkfn */*tree_chkfn*/,
922                          size_t /*tree_infosz*/,
923                          void */*tree_state*/, void */*user_state*/);
924   /* Check that a binary tree satisfies all of its invariants.
925    *
926    * Walk a binary tree, checking everything.  The only property that this
927    * function checks for itself is that each node is linked from only one
928    * parent.  All other checking is performed by caller-provided functions.
929    *
930    * There are two caller-provided checkers.  The `tree checker' is provided
931    * by the tree implementation, checking that the tree satisfies the
932    * necessary balance properties; the `user checker' is provided by the
933    * application, through the node class, and checks that the application's
934    * invariants are satisfied.
935    *
936    * Each of the two checkers has a /function/, which is called (several
937    * times) on each node in turn; a /state/ pointer, which is passed through
938    * to the function to track its overall state; and per-node /info/ pointers
939    * used to track perperties through the tree.  The tree checker function is
940    * provided as the TREE_CHKFN argument, and the user checker function is
941    * the `chk' operation in the node class CLS; the state pointers are
942    * provided as arguments TREE_STATE and USER_STATE; the walker allocates
943    * storage for the info structures as it traverses the tree, based on the
944    * TREE_INFOSZ argument for the tree checker, and the `infosz' class-
945    * operations member for the user checker.
946    *
947    * The ROOT argument is the /address/ of the tree's root link.  The root is
948    * not modified, but the address is printed in diagnostics.
949    *
950    * The F argument holds flags passed to checking functions.  No flags are
951    * currently defined, but the space is divided with six for the core
952    * (though likely of interest to all), five for tree implementations, and
953    * five for applications.
954    *
955    * Diagnostics are reported to FP, unless this is null.  Usually, `stderr'
956    * is a good choice.
957    *
958    * The walker operates as follows.
959    *
960    *   * If the link it has followed is null, then it calls the checking
961    *     functions with operation `XYLA_CHKOP_NIL' and returns to the parent.
962    *
963    *   * Otherwise, it notes that the current node has been seen on the
964    *     current traversal.  This currently involves rewriting the node's
965    *     links, so they are /not valid/ when the tree and user checkers are
966    *     invoked; the `struct xyla_bt_check' structure passed to the checker
967    *     functions contains the correct child links.
968    *
969    *   * It allocates per-node information storage for the checkers, and
970    *     calls the checker functions with operation `XYLA_CHKOP_SETUP' to
971    *     initialize their per-node storage.
972    *
973    *   * It calls the checker functions with operation `XYLA_CHKOP_BEFORE'.
974    *
975    *   * It visits the node's left child link.  If the left link is not null,
976    *     this will recursively allocate and set up the left child's node
977    *     information, which is provided to future calls to the checker.
978    *
979    *   * It calls the checker functions with operation `XYLA_CHKOP_MID'.
980    *
981    *   * It visits the node's right child link.  If the right link is not
982    *     null, this will recursively allocate and set up the right child's
983    *     node information, which is provided to future calls to the checker.
984    *
985    *   * It calls the checker functions with operation `XYLA_CHKOP_AFTER'.
986    *
987    *   * It calls the checker functions with operation `XYLA_CHKOP_TEARDOWN'
988    *     after calling the /parent/ with `XYLA_CHKOP_AFTER'.
989    *
990    * If a checker function returns a code other than `XYLA_RC_OK' or
991    * `XYLA_RC_BAD' then further processing is abbreviated: no new nodes are
992    * visited and only `XYLA_CHKOP_TEARDOWN' calls are made.
993    *
994    * If all the checker calls returned `XYLA_RC_OK' then the return value is
995    * `XYLA_RC_OK'; if any checker call returned `XYLA_RC_BAD', but none
996    * returned any other value, then the return value is `XYLA_RC_BAD';
997    * otherwise, the return value is the code from the failing checker call.
998    */
999
1000 struct xyla_bt_ordinfo {
1001   /* This is the node-information structure maintained by `xyla_bt_chkorder'
1002    * below.
1003    */
1004
1005   const void *lbound, *rbound;
1006 };
1007
1008 extern xyla_bt_chkfn xyla_bt_chkorder;
1009   /* A checking function to verify that the tree order respects the
1010    * ordering.
1011    */
1012
1013 #endif
1014
1015 /*----- That's all, folks -------------------------------------------------*/
1016
1017 #endif