3 * Basic binary tree operations
5 * (c) 2024 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Xyla, a library of binary trees.
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.
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.
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/>.
29 /*----- Header files ------------------------------------------------------*/
34 #ifndef XYLA_FREESTANDING
39 # define XYLA__ASSERT assert
43 # define XYLA__ASSERT(x) do (void)(x); while (0)
47 /*----- Data structures ---------------------------------------------------*/
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(_) \
57 _(HTCHG, "height changed") \
58 /* add new success codes at the bottom here */
61 #define XYLA__RC_DEFLOSE(tag, msg) XYLA__RCLOSE_##tag,
62 XYLA_RC_DOLOSE(XYLA__RC_DEFLOSE)
63 #undef XYLA__RC_DEFLOSE
68 #define XYLA__RC_DEFWIN(tag, msg) XYLA_RC_##tag,
69 XYLA_RC_DOWIN(XYLA__RC_DEFWIN)
70 #undef XYLA__RC_DEFWIN
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,
81 /* The intrusion into a binary tree node. */
83 struct xyla_bt_node *left, *right; /* links to left and right subtrees */
85 #define XYLA_BT_NODEPFX struct xyla_bt_node bt
86 #define XYLA_BT_NODEUSFX struct xyla_bt_node bt
88 struct xyla_bt_nodecls {
89 /* Tree node class. */
91 const struct xyla_bt_nodeops *ops; /* pointer to node operations */
95 /* Node position code. */
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 */
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.
108 typedef void xyla__dummyfn(void);
109 /* A dummy function, currently unused. Must be null for forwards
113 struct xyla_bt_nodeops {
114 /* Node operations table. */
118 xyla__dummyfn *_rsvd2, *_rsvd3;
120 #define XYLA_BT_NODEOPSPFX struct xyla_bt_nodeops node
121 #define XYLA_BT_NODEOPSUSFX struct xyla_bt_nodeops node
123 typedef int xyla_bt_navfn(struct xyla_bt_nodecls */*cls*/,
124 const struct xyla_bt_node */*node*/,
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.
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.
140 struct xyla_bt_ordopslots {
141 /* Ordering operations table. */
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; };
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.
162 /*----- Diagnostics -------------------------------------------------------*/
164 extern const char *xyla_strerror(int /*rc*/);
165 /* Return the message string associated with the return code RC. */
167 /*----- Iteration ---------------------------------------------------------*/
169 /* Background on iteration.
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.
175 * The invariant that we maintain is as follows.
177 * * If the stack is empty, then all nodes have been visited.
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
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
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
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.
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,
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.
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: \
221 * * if SP is zero, there are no more nodes; \
223 * * otherwise, the next NODE in order is STACK[--SP]; call again, \
224 * passing NODE->right to update the stack. \
226 * Similarly, to iterate right-to-left, pass BACK = `right' and pass \
227 * NODE->left to update. \
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. \
239 const struct xyla_bt_node *_node = (node), **_stack = (stack); \
240 int _sp = (sp), _max = (max); \
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; } \
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
256 /*----- Paths -------------------------------------------------------------*/
258 /* Background on paths.
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.
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
270 * PATH[i + 1] == &(*PATH[i])->left || PATH[i + 1] == &(*PATH[i])->right .
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
277 #define XYLA_BT_CURRENT(path, k) (*(path)[(k)])
278 /* Return the node currently designated by the PATH, or null if the path is
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; \
289 for (_i = 0; _i < _n; _i++) _newpath[_i] = _path[_i]; \
292 # define XYLA_BT_COPYPATH(newpath, path, k) do { \
293 memcpy((newpath), (path), \
294 ((k) + 1)*sizeof(struct xyla_bt_node **)); \
297 /* Copy the (K + 1) path entries from PATH to NEWPATH. */
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. \
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. \
310 struct xyla_bt_node *_node, *_next, \
311 **_root = (root), ***_path = (path); \
312 int _k, _htmax = (htmax); \
314 /* A path always begins with the root link. */ \
315 _k = 0; _path[0] = _root; _node = *_root; \
318 /* The tree is empty. The path is empty and covers only the root \
322 (node) = 0; (k) = _k; (rc) = XYLA_RC_OK; \
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 \
331 _next = _node->dir; \
333 { (node) = _node; (k) = _k; (rc) = XYLA_RC_OK; break; } \
334 else if (_k >= _htmax) \
335 { (rc) = XYLA_RC_TALL; (node) = 0; break; } \
337 { _path[++_k] = &_node->dir; _node = _next; } \
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 \
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. \
359 struct xyla_bt_node *_node0, *_node, *_next, \
360 **_link, **_plink, ***_path = (path); \
361 int _k0 = (k), _k = _k0, _htmax = (htmax); \
363 /* Collect the start node and the link address. */ \
364 _link = _path[_k]; _node0 = *_link; \
366 /* If there's a node, then we should explore the subtree on the \
367 * relevant side if there is one. \
370 _next = _node0->dir; \
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. \
377 { (rc) = XYLA_RC_TALL; (node) = 0; } \
379 _path[++_k] = &_node0->dir; _node = _next; \
381 _next = _node->opp; \
383 { (node) = _node; (k) = _k; (rc) = 0; break; } \
384 else if (_k >= _htmax) \
385 { (rc) = XYLA_RC_TALL; (node) = 0; break; } \
387 { _path[++_k] = &_node->opp; _node = _next; } \
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. \
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. \
410 { (node) = 0; /* `k' already correct */ (rc) = XYLA_RC_OK; } \
411 else if (_k >= _htmax) \
412 { (rc) = XYLA_RC_TALL; (node) = 0; } \
414 _path[++_k] = &_node0->dir; \
415 (node) = 0; (k) = _k; (rc) = XYLA_RC_OK; \
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; } \
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. \
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. \
443 struct xyla_bt_node *_node, ***_path = (path); \
444 int _k = (k), _htmax = (htmax); \
446 /* Collect the starting point, and check that the path is full. */ \
447 _node = *_path[_k]; XYLA__ASSERT(_node); \
449 /* Descend into the appropriate side subtree to find a null link. */ \
451 (rc) = XYLA_RC_TALL; \
453 _path[++_k] = &_node->dir; _node = _node->dir; \
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; } \
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. \
468 (node) = *((path)[0] = (root)); \
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 \
481 struct xyla_bt_node **_link, *_node, ***_path = (path); \
485 { (node) = 0; (pos) = XYLA_BTPOS_ROOT; } \
487 _link = _path[_k]; (node) = _node = *_path[--_k]; (k) = _k; \
488 (pos) = _link == &_node->left ? \
489 XYLA_BTPOS_LEFT : XYLA_BTPOS_RIGHT; \
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. \
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. \
504 struct xyla_bt_node *_node, ***_path = (path); \
505 int _k = (k), _htmax = (htmax); \
507 _node = *_path[_k]; XYLA__ASSERT(_node); \
509 { (rc) = XYLA_RC_TALL; (node) = 0; } \
511 _path[++_k] = &_node->dir; (k) = _k; \
512 (node) = _node->dir; (rc) = XYLA_RC_OK; \
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. \
523 struct xyla_bt_nodecls *_cls = (cls); \
524 xyla_bt_updfn *_updfn = _cls->ops->upd; \
525 struct xyla_bt_node **const *_path = (path); \
528 XYLA__ASSERT(*_path[_k]); while (_k) _updfn(_cls, *_path[--_k]); \
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 \
545 xyla_bt_ascendfn *_fn = (fn); \
546 struct xyla_bt_node *_node, **_nlink, *_parent, **_plink, \
547 **const *_path = (path); \
549 void *_arg = (arg); \
551 _nlink = _path[_k]; _node = *_nlink; \
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); \
558 _rc = _fn(_node, _parent, _parent->left, XYLA_BTPOS_RIGHT, _arg); \
559 if (_rc) { (rc) = _rc; break; } \
560 _nlink = _plink; _node = _parent; \
564 /*----- Searching ---------------------------------------------------------*/
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 \
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); \
580 /* If no NAVFN is provided, then see if there's one in the node \
584 _ops = (const struct xyla_bt_ordops *)_cls->ops; \
585 _navfn = _ops->ord.nav; \
588 /* Unsurprisingly, start at the root. */ \
591 /* Descend the tree. */ \
594 /* If we've reached the end, then give up. */ \
595 if (!_node) { (node) = 0; break; } \
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; } \
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 \
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. \
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. \
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; \
631 /* If no NAVFN is provided, then see if there's one in the node \
635 _ops = (const struct xyla_bt_ordops *)_cls->ops; \
636 _navfn = _ops->ord.nav; \
639 /* Unsurprisingly, start at the root. */ \
640 _path[0] = _root; _k = 0; _node = *_root; \
642 /* Descend the tree. */ \
645 /* If we've reached the end, then give up. */ \
646 if (!_node) { (node) = 0; (k) = _k; (rc) = XYLA_RC_OK; break; } \
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; } \
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; \
660 /*----- Removal -----------------------------------------------------------*/
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*/,
667 /* Remove a node from a binary tree.
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.
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'.
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.
690 * The modified nodes are all on the PATH; updating them is left for the
693 * Return `XYLA_RC_OK' on success.
696 /*----- Set operations ----------------------------------------------------*/
698 typedef int xyla_bt_joinfn(struct xyla_bt_nodecls */*cls*/,
699 struct xyla_bt_node **/*root_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.
711 typedef int xyla_bt_splitatfn(struct xyla_bt_nodecls */*cls*/,
712 struct xyla_bt_node **/*left_out*/,
714 struct xyla_bt_node **/*mid_out*/,
715 struct xyla_bt_node **/*right_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.
728 typedef int xyla_bt_splitrootfn(struct xyla_bt_node **/*left_out*/,
730 struct xyla_bt_node **/*root_out*/,
731 struct xyla_bt_node **/*right_out*/,
733 struct xyla_bt_node **/*root*/,
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.
742 struct xyla_bt_treeops {
743 /* Tree operations table. */
745 xyla_bt_joinfn *join;
746 xyla_bt_splitatfn *splitat;
747 xyla_bt_splitrootfn *splitroot;
750 struct xyla_bt_setopstack {
751 /* Stack entries for set operations. */
756 struct xyla_bt_node *a; int aht;
757 struct xyla_bt_node *b; int bht;
760 struct xyla_bt_node *uni; int uniht;
761 struct xyla_bt_node *isect; int isectht;
764 struct xyla_bt_node *diff; int diffht;
765 struct xyla_bt_node *isect; int isectht;
768 struct xyla_bt_node *am, *bm;
771 extern int xyla_bt_unisect(struct xyla_bt_nodecls */*cls*/,
772 struct xyla_bt_node **/*uni_out*/,
774 struct xyla_bt_node **/*isect_out*/,
775 int */*isectht_out*/,
776 struct xyla_bt_node **/*aroot*/,
778 struct xyla_bt_node **/*broot*/,
780 const struct xyla_bt_treeops */*ops*/,
781 struct xyla_bt_setopstack */*stack*/,
783 /* Compute the union and intersection of two trees.
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.
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
808 extern int xyla_bt_diffsect(struct xyla_bt_nodecls */*cls*/,
809 struct xyla_bt_node **/*diff_out*/,
811 struct xyla_bt_node **/*isect_out*/,
812 int */*isectht_out*/,
813 struct xyla_bt_node **/*aroot*/,
815 struct xyla_bt_node **/*broot*/,
816 const struct xyla_bt_treeops */*ops*/,
817 struct xyla_bt_setopstack */*stack*/,
819 /* Compute the set difference of the two operand trees.
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
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.
847 /*----- Checking ----------------------------------------------------------*/
849 #ifndef XYLA_FREESTANDING
852 /* Operation code passed to checking functions. */
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 */
862 struct xyla_bt_check;
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
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
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. */
880 struct xyla_bt_chkopslots {
881 /* Checking operations table. */
883 xyla_bt_chkfn *chk; size_t infosz;
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; };
891 struct xyla_bt_check {
892 /* Structure holding information passed to checking functions. */
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 */
908 extern void xyla_bt_bughdr(const char */*token*/,
909 struct xyla_bt_node *const */*root*/,
911 /* Begin reporting a bug found during checking. */
913 extern void xyla_bt_printnode(struct xyla_bt_nodecls */*cls*/,
914 const struct xyla_bt_node */*node*/,
916 /* Print a description of NODE to the stream FP. */
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.
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.
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.
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.
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.
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.
955 * Diagnostics are reported to FP, unless this is null. Usually, `stderr'
958 * The walker operates as follows.
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.
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.
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.
973 * * It calls the checker functions with operation `XYLA_CHKOP_BEFORE'.
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.
979 * * It calls the checker functions with operation `XYLA_CHKOP_MID'.
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.
985 * * It calls the checker functions with operation `XYLA_CHKOP_AFTER'.
987 * * It calls the checker functions with operation `XYLA_CHKOP_TEARDOWN'
988 * after calling the /parent/ with `XYLA_CHKOP_AFTER'.
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.
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.
1000 struct xyla_bt_ordinfo {
1001 /* This is the node-information structure maintained by `xyla_bt_chkorder'
1005 const void *lbound, *rbound;
1008 extern xyla_bt_chkfn xyla_bt_chkorder;
1009 /* A checking function to verify that the tree order respects the
1015 /*----- That's all, folks -------------------------------------------------*/