/** * Add item as left-sibling of node (cannot be the root node). * * This is inefficient if the node is not the first child (the head of the * sibling list) given that the siblings are linked through a one-way list. */ void etree_add_left_sibling(etree_t *tree, void *node, void *item) { node_t *n, *i; etree_check(tree); g_assert(node != NULL); g_assert(item != NULL); g_assert(etree_is_orphan(tree, item)); g_assert(!etree_is_root(tree, node)); n = ptr_add_offset(node, tree->offset); i = ptr_add_offset(item, tree->offset); i->parent = n->parent; i->sibling = n; if (n == n->parent->child) { /* node is first child, optimized case */ n->parent->child = i; } else { node_t *p; for (p = n->parent->child; p->sibling != n; p = p->sibling) /* empty */; g_assert(p != NULL); /* previous node found */ p->sibling = i; } tree->count = 0; /* Tree count is now unknown */ }
/** * Add item as right-sibling of node (cannot be the root node). */ void etree_add_right_sibling(etree_t *tree, void *node, void *item) { node_t *n, *i; etree_check(tree); g_assert(node != NULL); g_assert(item != NULL); g_assert(etree_is_orphan(tree, item)); g_assert(!etree_is_root(tree, node)); n = ptr_add_offset(node, tree->offset); i = ptr_add_offset(item, tree->offset); i->parent = n->parent; i->sibling = n->sibling; n->sibling = i; if (NULL == i->sibling && etree_is_extended(tree)) { nodex_t *px = (nodex_t *) n->parent; px->last_child = i; } tree->count = 0; /* Tree count is now unknown */ }
/** * Prepend child to parent. * * This is always a fast operation. */ void etree_prepend_child(etree_t *tree, void *parent, void *child) { node_t *cn, *pn; etree_check(tree); g_assert(parent != NULL); g_assert(child != NULL); g_assert(etree_is_orphan(tree, child)); cn = ptr_add_offset(child, tree->offset); pn = ptr_add_offset(parent, tree->offset); cn->parent = pn; cn->sibling = pn->child; pn->child = cn; if (etree_is_extended(tree)) { nodex_t *px = (nodex_t *) pn; if (NULL == px->last_child) { g_assert(NULL == cn->sibling); /* Parent did not have any child */ px->last_child = cn; } } tree->count = 0; /* Tree count is now unknown */ }
/** * Make sure node is orphan. */ static void xnode_orphan_check(const xnode_t * const xn) { etree_t t; xnode_check(xn); etree_init_root(&t, xn, TRUE, offsetof(xnode_t, node)); g_assert(etree_is_orphan(&t, xn)); }
/** * Append child to parent. * * If this is a frequent operation, consider using an extended tree. */ void etree_append_child(etree_t *tree, void *parent, void *child) { node_t *cn, *pn; etree_check(tree); g_assert(parent != NULL); g_assert(child != NULL); g_assert(etree_is_orphan(tree, child)); cn = ptr_add_offset(child, tree->offset); pn = ptr_add_offset(parent, tree->offset); if (etree_is_extended(tree)) { nodex_t *px = ptr_add_offset(parent, tree->offset); if (px->last_child != NULL) { node_t *lcn = px->last_child; g_assert(0 == ptr_cmp(lcn->parent, px)); g_assert(NULL == lcn->sibling); lcn->sibling = cn; } else { g_assert(NULL == px->child); px->child = cn; } px->last_child = cn; } else { if (NULL == pn->child) { pn->child = cn; } else { node_t *lcn = etree_node_last_sibling(pn->child); lcn->sibling = cn; } } cn->parent = pn; tree->count = 0; /* Tree count is now unknown */ }
/** * Computes the root of the tree, starting from any item. * * This disregards the actual root in the etree_t structure passed, which may * be inaccurate, i.e. a sub-node of the actual tree. The only accurate * information that etree_t must contain is the offset of the node_t within * the items. * * @param tree the tree descriptor (with possible inaccurate root) * @param item an item belonging to the tree * * @return the root of the tree to which item belongs. */ void * etree_find_root(const etree_t *tree, const void *item) { const node_t *n, *p; void *root; etree_check(tree); g_assert(item != NULL); n = const_ptr_add_offset(item, tree->offset); for (p = n; p != NULL; p = n->parent) n = p; root = ptr_add_offset(deconstify_pointer(n), -tree->offset); g_assert(etree_is_orphan(tree, root)); /* No parent, no sibling */ return root; }