/* run tests against the c_rbtree_find*() helpers */ static void test_map(void) { CRBNode **slot, *p; CRBTree t = {}; Node *nodes[2048]; unsigned long i; /* allocate and initialize all nodes */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { nodes[i] = malloc(sizeof(*nodes[i])); assert(nodes[i]); nodes[i]->key = i; c_rbnode_init(&nodes[i]->rb); } /* shuffle nodes */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); /* add all nodes, and verify that each node is linked */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { assert(!c_rbnode_is_linked(&nodes[i]->rb)); assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p); assert(slot); c_rbtree_add(&t, p, slot, &nodes[i]->rb); assert(c_rbnode_is_linked(&nodes[i]->rb)); assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); } /* shuffle nodes again */ shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); /* remove all nodes (in different order) */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { assert(c_rbnode_is_linked(&nodes[i]->rb)); assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); c_rbtree_remove_init(&t, &nodes[i]->rb); assert(!c_rbnode_is_linked(&nodes[i]->rb)); assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); } /* free nodes again */ for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) free(nodes[i]); }
static void test_parent_middle(TestContext *ctx) { size_t i; shuffle(ctx->nodes, ctx->n_nodes); for (i = 0; i < ctx->n_nodes; ++i) child_assert(c_rbnode_is_linked(ctx->nodes[i])); }
static void test_child2(TestContext *ctx) { size_t i; for (i = 0; i < ctx->n_nodes; ++i) { child_assert(c_rbnode_is_linked(ctx->nodes[i])); c_rbnode_unlink(ctx->nodes[i]); } }
static void test_child1(TestContext *ctx) { CRBNode *p, **slot; size_t i; for (i = 0; i < ctx->n_nodes; ++i) { child_assert(!c_rbnode_is_linked(ctx->nodes[i])); slot = c_rbtree_find_slot(ctx->tree, compare, ctx->nodes[i], &p); c_rbtree_add(ctx->tree, p, slot, ctx->nodes[i]); } }
static void test_parent_end(TestContext *ctx) { size_t i; int r; for (i = 0; i < ctx->n_nodes; ++i) c_assert(!c_rbnode_is_linked(ctx->nodes[i])); r = munmap(ctx->map, ctx->mapsize); c_assert(r >= 0); }
/** * c_rbnode_next_postorder() - return next node in post-order * @n: current node, or NULL * * This returns the next node to @n, based on a left-to-right post-order * traversal. If @n is NULL, the root node, or unlinked, this returns NULL. * * This implements a left-to-right post-order traversal: First visit the left * child of a node, then the right, and lastly the node itself. Children are * traversed recursively. * * This function can be used to implement a left-to-right post-order traversal: * * for (n = c_rbtree_first_postorder(t); n; n = c_rbnode_next_postorder(n)) * visit(n); * * Worst case runtime (n: number of elements in tree): O(log(n)) * * Return: Pointer to next node, or NULL. */ _c_public_ CRBNode *c_rbnode_next_postorder(CRBNode *n) { CRBNode *p; if (!c_rbnode_is_linked(n)) return NULL; p = c_rbnode_parent(n); if (p && n == p->left && p->right) return c_rbnode_leftdeepest(p->right); return p; }
/* verify that all API calls are exported */ static void test_api(void) { CRBTree t = {}; CRBNode n = C_RBNODE_INIT(n); assert(!c_rbnode_is_linked(&n)); /* init, is_linked, add, remove, remove_init */ c_rbtree_add(&t, NULL, &t.root, &n); assert(c_rbnode_is_linked(&n)); c_rbtree_remove_init(&t, &n); assert(!c_rbnode_is_linked(&n)); c_rbtree_add(&t, NULL, &t.root, &n); assert(c_rbnode_is_linked(&n)); c_rbtree_remove(&t, &n); assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */ c_rbnode_init(&n); assert(!c_rbnode_is_linked(&n)); /* first, last, leftmost, rightmost, next, prev */ assert(!c_rbtree_first(&t)); assert(!c_rbtree_last(&t)); assert(&n == c_rbnode_leftmost(&n)); assert(&n == c_rbnode_rightmost(&n)); assert(!c_rbnode_next(&n)); assert(!c_rbnode_prev(&n)); }
/** * c_rbnode_prev() - return previous node * @n: current node, or NULL * * An RB-Tree always defines a linear order of its elements. This function * returns the logically previous node to @n. If @n is NULL, the first node or * unlinked, this returns NULL. * * Worst case runtime (n: number of elements in tree): O(log(n)) * * Return: Pointer to previous node, or NULL. */ _c_public_ CRBNode *c_rbnode_prev(CRBNode *n) { CRBNode *p; if (!c_rbnode_is_linked(n)) return NULL; if (n->left) return c_rbnode_rightmost(n->left); while ((p = c_rbnode_parent(n)) && n == p->left) n = p; return p; }
/** * c_rbnode_prev_postorder() - return previous node in post-order * @n: current node, or NULL * * This returns the previous node to @n, based on a left-to-right post-order * traversal. That is, it is the inverse operation to c_rbnode_next_postorder(). * If @n is NULL, the left-deepest node, or unlinked, this returns NULL. * * This function returns the logical previous node in a directed post-order * traversal. That is, it effectively does a pre-order traversal (since a * reverse post-order traversal is a pre-order traversal). This function does * NOT do a right-to-left post-order traversal! In other words, the following * invariant is guaranteed, if c_rbnode_next_postorder(n) is non-NULL: * * n == c_rbnode_prev_postorder(c_rbnode_next_postorder(n)) * * This function can be used to implement a right-to-left pre-order traversal, * using the fact that a reverse post-order traversal is also a valid pre-order * traversal: * * for (n = c_rbtree_last_postorder(t); n; n = c_rbnode_prev_postorder(n)) * visit(n); * * This would effectively perform a right-to-left pre-order traversal: first * visit a parent, then its right child, then its left child. Both children are * traversed recursively. * * Worst case runtime (n: number of elements in tree): O(log(n)) * * Return: Pointer to previous node in post-order, or NULL. */ _c_public_ CRBNode *c_rbnode_prev_postorder(CRBNode *n) { CRBNode *p; if (!c_rbnode_is_linked(n)) return NULL; if (n->right) return n->right; if (n->left) return n->left; while ((p = c_rbnode_parent(n))) { if (p->left && n != p->left) return p->left; n = p; } return NULL; }
static void insert(CRBTree *t, CRBNode *n) { CRBNode **i, *p; assert(t); assert(n); assert(!c_rbnode_is_linked(n)); i = &t->root; p = NULL; while (*i) { p = *i; if (n < *i) { i = &(*i)->left; } else { assert(n > *i); i = &(*i)->right; } } c_rbtree_add(t, p, i, n); }