/* Initializes |trav| for use with |tree| and selects the null node. */ void rtbst_t_init (struct rtbst_traverser *trav, struct rtbst_table *tree) { trav->rtbst_table = tree; trav->rtbst_node = NULL; } /* Initializes |trav| for |tree|. Returns data item in |tree| with the least value, or |NULL| if |tree| is empty. */ void * rtbst_t_first (struct rtbst_traverser *trav, struct rtbst_table *tree) { assert (tree != NULL && trav != NULL); trav->rtbst_table = tree; trav->rtbst_node = tree->rtbst_root; if (trav->rtbst_node != NULL) { while (trav->rtbst_node->rtbst_link[0] != NULL) trav->rtbst_node = trav->rtbst_node->rtbst_link[0]; return trav->rtbst_node->rtbst_data; } else return NULL; } /* Initializes |trav| for |tree|. Returns data item in |tree| with the greatest value, or |NULL| if |tree| is empty. */ void * rtbst_t_last (struct rtbst_traverser *trav, struct rtbst_table *tree) { assert (tree != NULL && trav != NULL); trav->rtbst_table = tree; trav->rtbst_node = tree->rtbst_root; if (trav->rtbst_node != NULL) { while (trav->rtbst_node->rtbst_rtag == RTBST_CHILD) trav->rtbst_node = trav->rtbst_node->rtbst_link[1]; return trav->rtbst_node->rtbst_data; } else return NULL; } /* Searches for |item| in |tree|. If found, initializes |trav| to the item found and returns the item as well. If there is no matching item, initializes |trav| to the null item and returns |NULL|. */ void * rtbst_t_find (struct rtbst_traverser *trav, struct rtbst_table *tree, void *item) { struct rtbst_node *p; assert (trav != NULL && tree != NULL && item != NULL); trav->rtbst_table = tree; trav->rtbst_node = NULL; p = tree->rtbst_root; if (p == NULL) return NULL; for (;;) { int cmp = tree->rtbst_compare (item, p->rtbst_data, tree->rtbst_param); if (cmp == 0) { trav->rtbst_node = p; return p->rtbst_data; } if (cmp < 0) { p = p->rtbst_link[0]; if (p == NULL) return NULL; } else { if (p->rtbst_rtag == RTBST_THREAD) return NULL; p = p->rtbst_link[1]; } } } /* Attempts to insert |item| into |tree|. If |item| is inserted successfully, it is returned and |trav| is initialized to its location. If a duplicate is found, it is returned and |trav| is initialized to its location. No replacement of the item occurs. If a memory allocation failure occurs, |NULL| is returned and |trav| is initialized to the null item. */ void * rtbst_t_insert (struct rtbst_traverser *trav, struct rtbst_table *tree, void *item) { void **p; assert (trav != NULL && tree != NULL && item != NULL); p = rtbst_probe (tree, item); if (p != NULL) { trav->rtbst_table = tree; trav->rtbst_node = ((struct rtbst_node *) ((char *) p - offsetof (struct rtbst_node, rtbst_data))); return *p; } else { rtbst_t_init (trav, tree); return NULL; } } /* Initializes |trav| to have the same current node as |src|. */ void * rtbst_t_copy (struct rtbst_traverser *trav, const struct rtbst_traverser *src) { assert (trav != NULL && src != NULL); trav->rtbst_table = src->rtbst_table; trav->rtbst_node = src->rtbst_node; return trav->rtbst_node != NULL ? trav->rtbst_node->rtbst_data : NULL; } /* Returns the next data item in inorder within the tree being traversed with |trav|, or if there are no more data items returns |NULL|. */ void * rtbst_t_next (struct rtbst_traverser *trav) { assert (trav != NULL); if (trav->rtbst_node == NULL) return rtbst_t_first (trav, trav->rtbst_table); else if (trav->rtbst_node->rtbst_rtag == RTBST_THREAD) { trav->rtbst_node = trav->rtbst_node->rtbst_link[1]; return trav->rtbst_node != NULL ? trav->rtbst_node->rtbst_data : NULL; } else { trav->rtbst_node = trav->rtbst_node->rtbst_link[1]; while (trav->rtbst_node->rtbst_link[0] != NULL) trav->rtbst_node = trav->rtbst_node->rtbst_link[0]; return trav->rtbst_node->rtbst_data; } } /* Returns the previous data item in inorder within the tree being traversed with |trav|, or if there are no more data items returns |NULL|. */ void * rtbst_t_prev (struct rtbst_traverser *trav) { assert (trav != NULL); if (trav->rtbst_node == NULL) return rtbst_t_last (trav, trav->rtbst_table); else if (trav->rtbst_node->rtbst_link[0] == NULL) { rtbst_comparison_func *cmp = trav->rtbst_table->rtbst_compare; void *param = trav->rtbst_table->rtbst_param; struct rtbst_node *node = trav->rtbst_node; struct rtbst_node *i; trav->rtbst_node = NULL; for (i = trav->rtbst_table->rtbst_root; i != node; ) { int dir = cmp (node->rtbst_data, i->rtbst_data, param) > 0; if (dir == 1) trav->rtbst_node = i; i = i->rtbst_link[dir]; } return trav->rtbst_node != NULL ? trav->rtbst_node->rtbst_data : NULL; } else { trav->rtbst_node = trav->rtbst_node->rtbst_link[0]; while (trav->rtbst_node->rtbst_rtag == RTBST_CHILD) trav->rtbst_node = trav->rtbst_node->rtbst_link[1]; return trav->rtbst_node->rtbst_data; } } /* Returns |trav|'s current item. */ void * rtbst_t_cur (struct rtbst_traverser *trav) { assert (trav != NULL); return trav->rtbst_node != NULL ? trav->rtbst_node->rtbst_data : NULL; } /* Replaces the current item in |trav| by |new| and returns the item replaced. |trav| must not have the null item selected. The new item must not upset the ordering of the tree. */ void * rtbst_t_replace (struct rtbst_traverser *trav, void *new) { void *old; assert (trav != NULL && trav->rtbst_node != NULL && new != NULL); old = trav->rtbst_node->rtbst_data; trav->rtbst_node->rtbst_data = new; return old; }