Beispiel #1
0
/* 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]);
}
Beispiel #2
0
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]));
}
Beispiel #3
0
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]);
        }
}
Beispiel #4
0
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]);
        }
}
Beispiel #5
0
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);
}
Beispiel #6
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;
}
Beispiel #7
0
/* 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));
}
Beispiel #8
0
/**
 * 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;
}
Beispiel #9
0
/**
 * 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;
}
Beispiel #10
0
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);
}