static void _gtk_rbnode_rotate_right (GtkRBTree *tree, GtkRBNode *node) { gint node_height, left_height; GtkRBNode *left; g_return_if_fail (!_gtk_rbtree_is_nil (node)); g_return_if_fail (!_gtk_rbtree_is_nil (node->left)); left = node->left; node_height = GTK_RBNODE_GET_HEIGHT (node); left_height = GTK_RBNODE_GET_HEIGHT (left); node->left = left->right; if (!_gtk_rbtree_is_nil (left->right)) left->right->parent = node; left->parent = node->parent; if (!_gtk_rbtree_is_nil (node->parent)) { if (node == node->parent->right) node->parent->right = left; else node->parent->left = left; } else { tree->root = left; } /* link node and left */ left->right = node; node->parent = left; node->count = 1 + node->left->count + node->right->count; left->count = 1 + left->left->count + left->right->count; node->offset = node_height + node->left->offset + node->right->offset + (node->children ? node->children->root->offset : 0); left->offset = left_height + left->left->offset + left->right->offset + (left->children?left->children->root->offset:0); _fixup_validation (tree, node); _fixup_validation (tree, left); _fixup_total_count (tree, node); _fixup_total_count (tree, left); }
static void _gtk_rbtree_test_height (GtkRBTree *tree, GtkRBNode *node) { gint computed_offset = 0; /* This whole test is sort of a useless truism. */ if (!_gtk_rbtree_is_nil (node->left)) computed_offset += node->left->offset; if (!_gtk_rbtree_is_nil (node->right)) computed_offset += node->right->offset; if (node->children && !_gtk_rbtree_is_nil (node->children->root)) computed_offset += node->children->root->offset; if (GTK_RBNODE_GET_HEIGHT (node) + computed_offset != node->offset) g_error ("node has broken offset\n"); if (!_gtk_rbtree_is_nil (node->left)) _gtk_rbtree_test_height (tree, node->left); if (!_gtk_rbtree_is_nil (node->right)) _gtk_rbtree_test_height (tree, node->right); if (node->children && !_gtk_rbtree_is_nil (node->children->root)) _gtk_rbtree_test_height (node->children, node->children->root); }
static void test_reorder (void) { guint n = g_test_perf () ? 1000000 : 100; GtkRBTree *tree; GtkRBNode *node; gint *reorder; guint i; double elapsed; reorder = fisher_yates_shuffle (n); tree = create_unsorted_tree (reorder, n); g_test_timer_start (); _gtk_rbtree_reorder (tree, reorder, n); elapsed = g_test_timer_elapsed (); if (g_test_perf ()) g_test_minimized_result (elapsed, "reordering rbtree with %u items: %gsec", n, elapsed); _gtk_rbtree_test (tree); for (node = _gtk_rbtree_first (tree), i = 0; node != NULL; node = _gtk_rbtree_next (tree, node), i++) { g_assert (GTK_RBNODE_GET_HEIGHT (node) == i); } g_assert (i == n); _gtk_rbtree_free (tree); }
gint _gtk_rbtree_node_find_offset (GtkRBTree *tree, GtkRBNode *node) { GtkRBNode *last; gint retval; g_assert (node); g_assert (node->left); retval = node->left->offset; while (tree && node && !_gtk_rbtree_is_nil (node)) { last = node; node = node->parent; /* Add left branch, plus children, iff we came from the right */ if (node->right == last) retval += node->offset - node->right->offset; if (_gtk_rbtree_is_nil (node)) { node = tree->parent_node; tree = tree->parent_tree; /* Add the parent node, plus the left branch. */ if (node) retval += node->left->offset + GTK_RBNODE_GET_HEIGHT (node); } } return retval; }
void _gtk_rbtree_node_set_height (GtkRBTree *tree, GtkRBNode *node, gint height) { gint diff = height - GTK_RBNODE_GET_HEIGHT (node); GtkRBNode *tmp_node = node; GtkRBTree *tmp_tree = tree; if (diff == 0) return; while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil) { tmp_node->offset += diff; tmp_node = tmp_node->parent; if (tmp_node == tmp_tree->nil) { tmp_node = tmp_tree->parent_node; tmp_tree = tmp_tree->parent_tree; } } #ifdef G_ENABLE_DEBUG if (gtk_debug_flags & GTK_DEBUG_TREE) _gtk_rbtree_test (G_STRLOC, tree); #endif }
static void _gtk_rbnode_rotate_left (GtkRBTree *tree, GtkRBNode *node) { gint node_height, right_height; GtkRBNode *right; g_return_if_fail (!_gtk_rbtree_is_nil (node)); g_return_if_fail (!_gtk_rbtree_is_nil (node->right)); right = node->right; node_height = GTK_RBNODE_GET_HEIGHT (node); right_height = GTK_RBNODE_GET_HEIGHT (right); node->right = right->left; if (!_gtk_rbtree_is_nil (right->left)) right->left->parent = node; right->parent = node->parent; if (!_gtk_rbtree_is_nil (node->parent)) { if (node == node->parent->left) node->parent->left = right; else node->parent->right = right; } else { tree->root = right; } right->left = node; node->parent = right; node->count = 1 + node->left->count + node->right->count; right->count = 1 + right->left->count + right->right->count; node->offset = node_height + node->left->offset + node->right->offset + (node->children ? node->children->root->offset : 0); right->offset = right_height + right->left->offset + right->right->offset + (right->children ? right->children->root->offset : 0); _fixup_validation (tree, node); _fixup_validation (tree, right); _fixup_total_count (tree, node); _fixup_total_count (tree, right); }
void _gtk_rbtree_node_set_height (GtkRBTree *tree, GtkRBNode *node, gint height) { gint diff = height - GTK_RBNODE_GET_HEIGHT (node); if (diff == 0) return; gtk_rbnode_adjust (tree, node, 0, 0, diff); #ifdef G_ENABLE_DEBUG if (gtk_get_debug_flags () & GTK_DEBUG_TREE) _gtk_rbtree_test (G_STRLOC, tree); #endif }
void _gtk_rbtree_remove_node (GtkRBTree *tree, GtkRBNode *node) { GtkRBNode *x, *y; gint y_height; guint y_total_count; g_return_if_fail (tree != NULL); g_return_if_fail (node != NULL); #ifdef G_ENABLE_DEBUG if (gtk_get_debug_flags () & GTK_DEBUG_TREE) { g_print ("\n\n_gtk_rbtree_remove_node: %p\n", node); _gtk_rbtree_debug_spew (tree); _gtk_rbtree_test (G_STRLOC, tree); } #endif /* G_ENABLE_DEBUG */ /* make sure we're deleting a node that's actually in the tree */ for (x = node; !_gtk_rbtree_is_nil (x->parent); x = x->parent) ; g_return_if_fail (x == tree->root); #ifdef G_ENABLE_DEBUG if (gtk_get_debug_flags () & GTK_DEBUG_TREE) _gtk_rbtree_test (G_STRLOC, tree); #endif if (_gtk_rbtree_is_nil (node->left) || _gtk_rbtree_is_nil (node->right)) { y = node; } else { y = node->right; while (!_gtk_rbtree_is_nil (y->left)) y = y->left; } y_height = GTK_RBNODE_GET_HEIGHT (y) + (y->children ? y->children->root->offset : 0); y_total_count = 1 + (y->children ? y->children->root->total_count : 0); /* x is y's only child, or nil */ if (!_gtk_rbtree_is_nil (y->left)) x = y->left; else x = y->right; /* remove y from the parent chain */ if (!_gtk_rbtree_is_nil (x)) x->parent = y->parent; if (!_gtk_rbtree_is_nil (y->parent)) { if (y == y->parent->left) y->parent->left = x; else y->parent->right = x; } else { tree->root = x; } /* We need to clean up the validity of the tree. */ gtk_rbnode_adjust (tree, y, -1, - y_total_count, - y_height); if (GTK_RBNODE_GET_COLOR (y) == GTK_RBNODE_BLACK) _gtk_rbtree_remove_node_fixup (tree, x, y->parent); if (y != node) { gint node_height, node_total_count; /* We want to see how much we remove from the aggregate values. * This is all the children we remove plus the node's values. */ node_height = GTK_RBNODE_GET_HEIGHT (node) + (node->children ? node->children->root->offset : 0); node_total_count = 1 + (node->children ? node->children->root->total_count : 0); /* Move the node over */ if (GTK_RBNODE_GET_COLOR (node) != GTK_RBNODE_GET_COLOR (y)) y->flags ^= (GTK_RBNODE_BLACK | GTK_RBNODE_RED); y->left = node->left; if (!_gtk_rbtree_is_nil (y->left)) y->left->parent = y; y->right = node->right; if (!_gtk_rbtree_is_nil (y->right)) y->right->parent = y; y->parent = node->parent; if (!_gtk_rbtree_is_nil (y->parent)) { if (y->parent->left == node) y->parent->left = y; else y->parent->right = y; } else { tree->root = y; } y->count = node->count; y->total_count = node->total_count; y->offset = node->offset; gtk_rbnode_adjust (tree, y, 0, y_total_count - node_total_count, y_height - node_height); } _gtk_rbnode_free (node); #ifdef G_ENABLE_DEBUG if (gtk_get_debug_flags () & GTK_DEBUG_TREE) { g_print ("_gtk_rbtree_remove_node finished...\n"); _gtk_rbtree_debug_spew (tree); g_print ("\n\n"); _gtk_rbtree_test (G_STRLOC, tree); } #endif /* G_ENABLE_DEBUG */ }
/* It basically pulls everything out of the tree, rearranges it, and puts it * back together. Our strategy is to keep the old RBTree intact, and just * rearrange the contents. When that is done, we go through and update the * heights. There is probably a more elegant way to write this function. If * anyone wants to spend the time writing it, patches will be accepted. */ void _gtk_rbtree_reorder (GtkRBTree *tree, gint *new_order, gint length) { GtkRBReorder reorder = { NULL }; GArray *array; GtkRBNode *node; gint i; g_return_if_fail (tree != NULL); g_return_if_fail (length > 0); g_return_if_fail (tree->root->count == length); /* Sort the trees values in the new tree. */ array = g_array_sized_new (FALSE, FALSE, sizeof (GtkRBReorder), length); for (i = 0; i < length; i++) { reorder.order = new_order[i]; reorder.invert_order = i; g_array_append_val (array, reorder); } g_array_sort(array, gtk_rbtree_reorder_sort_func); /* rewind node*/ node = tree->root; while (node && node->left != tree->nil) node = node->left; for (i = 0; i < length; i++) { g_assert (node != tree->nil); g_array_index (array, GtkRBReorder, i).children = node->children; g_array_index (array, GtkRBReorder, i).flags = GTK_RBNODE_NON_COLORS & node->flags; g_array_index (array, GtkRBReorder, i).height = GTK_RBNODE_GET_HEIGHT (node); node = _gtk_rbtree_next (tree, node); } g_array_sort (array, gtk_rbtree_reorder_invert_func); /* rewind node*/ node = tree->root; while (node && node->left != tree->nil) node = node->left; /* Go through the tree and change the values to the new ones. */ for (i = 0; i < length; i++) { reorder = g_array_index (array, GtkRBReorder, i); node->children = reorder.children; if (node->children) node->children->parent_node = node; node->flags = GTK_RBNODE_GET_COLOR (node) | reorder.flags; /* We temporarily set the height to this. */ node->offset = reorder.height; node = _gtk_rbtree_next (tree, node); } gtk_rbtree_reorder_fixup (tree, tree->root); g_array_free (array, TRUE); }
void _gtk_rbtree_remove_node (GtkRBTree *tree, GtkRBNode *node) { GtkRBNode *x, *y; GtkRBTree *tmp_tree; GtkRBNode *tmp_node; gint y_height; g_return_if_fail (tree != NULL); g_return_if_fail (node != NULL); #ifdef G_ENABLE_DEBUG if (gtk_debug_flags & GTK_DEBUG_TREE) { g_print ("\n\n_gtk_rbtree_remove_node: %p\n", node); _gtk_rbtree_debug_spew (tree); _gtk_rbtree_test (G_STRLOC, tree); } #endif /* G_ENABLE_DEBUG */ /* make sure we're deleting a node that's actually in the tree */ for (x = node; x->parent != tree->nil; x = x->parent) ; g_return_if_fail (x == tree->root); #ifdef G_ENABLE_DEBUG if (gtk_debug_flags & GTK_DEBUG_TREE) _gtk_rbtree_test (G_STRLOC, tree); #endif if (node->left == tree->nil || node->right == tree->nil) { y = node; } else { y = node->right; while (y->left != tree->nil) y = y->left; } /* adjust count only beneath tree */ for (x = y; x != tree->nil; x = x->parent) { x->count--; } /* offsets and parity adjust all the way up through parent trees */ y_height = GTK_RBNODE_GET_HEIGHT (y); tmp_tree = tree; tmp_node = y; while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil) { tmp_node->offset -= (y_height + (y->children?y->children->root->offset:0)); _fixup_validation (tmp_tree, tmp_node); _fixup_parity (tmp_tree, tmp_node); tmp_node = tmp_node->parent; if (tmp_node == tmp_tree->nil) { tmp_node = tmp_tree->parent_node; tmp_tree = tmp_tree->parent_tree; } } /* x is y's only child, or nil */ if (y->left != tree->nil) x = y->left; else x = y->right; /* remove y from the parent chain */ x->parent = y->parent; if (y->parent != tree->nil) { if (y == y->parent->left) y->parent->left = x; else y->parent->right = x; } else { tree->root = x; } /* We need to clean up the validity of the tree. */ tmp_tree = tree; tmp_node = x; do { /* We skip the first time, iff x is nil */ if (tmp_node != tmp_tree->nil) { _fixup_validation (tmp_tree, tmp_node); _fixup_parity (tmp_tree, tmp_node); } tmp_node = tmp_node->parent; if (tmp_node == tmp_tree->nil) { tmp_node = tmp_tree->parent_node; tmp_tree = tmp_tree->parent_tree; } } while (tmp_tree != NULL); if (y != node) { gint diff; /* Copy the node over */ if (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK) node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_BLACK); else node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_RED); node->children = y->children; if (y->children) { node->children = y->children; node->children->parent_node = node; } else { node->children = NULL; } _fixup_validation (tree, node); _fixup_parity (tree, node); /* We want to see how different our height is from the previous node. * To do this, we compare our current height with our supposed height. */ diff = y_height - GTK_RBNODE_GET_HEIGHT (node); tmp_tree = tree; tmp_node = node; while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil) { tmp_node->offset += diff; _fixup_validation (tmp_tree, tmp_node); _fixup_parity (tmp_tree, tmp_node); tmp_node = tmp_node->parent; if (tmp_node == tmp_tree->nil) { tmp_node = tmp_tree->parent_node; tmp_tree = tmp_tree->parent_tree; } } } if (GTK_RBNODE_GET_COLOR (y) == GTK_RBNODE_BLACK) _gtk_rbtree_remove_node_fixup (tree, x); _gtk_rbnode_free (y); #ifdef G_ENABLE_DEBUG if (gtk_debug_flags & GTK_DEBUG_TREE) { g_print ("_gtk_rbtree_remove_node finished...\n"); _gtk_rbtree_debug_spew (tree); g_print ("\n\n"); _gtk_rbtree_test (G_STRLOC, tree); } #endif /* G_ENABLE_DEBUG */ }