From: Dana Jansens Date: Fri, 30 Oct 2009 22:16:48 +0000 (-0400) Subject: Fixes to maintain consistency in the tree while versioning. X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=d4cf6a7490002ade8e5aa858f297e44d4bc0eba2;p=dana%2Fcg-glib.git Fixes to maintain consistency in the tree while versioning. --- diff --git a/glib/gtree.c b/glib/gtree.c index cd850b69..59be18f5 100644 --- a/glib/gtree.c +++ b/glib/gtree.c @@ -500,6 +500,9 @@ static GTreeNode* g_tree_node_next_version (GTree *tree, GTreeNode *node) { + if (!node) + return NULL; + g_assert(node->version(NOW) <= tree->version); if (node->version(NOW) == tree->version) @@ -768,12 +771,16 @@ g_tree_insert_internal (GTree *tree, while (node->parent(NOW) && g_tree_priority (node) < g_tree_priority (node->parent(NOW))) { - GTreeNode *const sp = node->parent(NOW)->parent(NOW); - GTreeNode *const p = node->parent(NOW); + GTreeNode *sp, *p; + + /* we'll be changing both of these nodes */ + p = g_tree_node_next_version (tree, node->parent(NOW)); + sp = g_tree_node_next_version (tree, p->parent(NOW)); + if (p->left(NOW) == node) - g_tree_node_rotate_right (tree, p); + node = g_tree_node_rotate_right (tree, p); else - g_tree_node_rotate_left (tree, p); + node = g_tree_node_rotate_left (tree, p); if (!sp) { @@ -781,9 +788,9 @@ g_tree_insert_internal (GTree *tree, tree->roots[0].root = node; } else if (sp->left(NOW) == p) - sp->left(NOW) = node; + sp->v[0].left = node; else - sp->right(NOW) = node; + sp->v[0].right = node; } } @@ -897,6 +904,10 @@ g_tree_remove_internal (GTree *tree, /* rotate the node down the tree, maintaining the heap property */ while (node->left_child(NOW) || node->right_child(NOW)) { + /* we're changing this node, make sure our pointer will stay valid + when we rotate it */ + node = g_tree_node_next_version (tree, node); + if (!node->left_child(NOW) || (node->right_child(NOW) && g_tree_priority (node->left(NOW)) > @@ -964,16 +975,25 @@ g_tree_remove_internal (GTree *tree, parent->v[0].right = node->right(NOW); } } - - if (!steal) + + /* only really delete the node if it's in the current version, otherwise + it needs to be remembered */ + if (node->nv == 1 && node->version(NOW) == tree->version) { - if (tree->key_destroy_func) - tree->key_destroy_func (node->data->key); - if (tree->value_destroy_func) - tree->value_destroy_func (node->data->value); - } + if (!steal) + { + if (tree->key_destroy_func) + tree->key_destroy_func (node->data->key); + if (tree->value_destroy_func) + tree->value_destroy_func (node->data->value); + } - g_slice_free (GTreeNode, node); + g_slice_free (GTreeNodeData, node->data); + g_slice_free1 (sizeof(GTreeNodeVersion) * + (node->version(NOW) == 0 ? 1 : MAX_IN_DEGREE + 1), + node->v); + g_slice_free (GTreeNode, node); + } tree->nnodes--; @@ -1434,10 +1454,9 @@ g_tree_node_rotate_left (GTree *tree, { GTreeNode *right; - right = node->right(NOW); + g_assert (node->version(NOW) == tree->version); - node = g_tree_node_next_version (tree, node); - right = g_tree_node_next_version (tree, right); + right = g_tree_node_next_version (tree, node->right(NOW)); if (right->left_child(NOW)) { @@ -1463,10 +1482,9 @@ g_tree_node_rotate_right (GTree *tree, { GTreeNode *left; - left = node->left(NOW); + g_assert (node->version(NOW) == tree->version); - node = g_tree_node_next_version (tree, node); - left = g_tree_node_next_version (tree, left); + left = g_tree_node_next_version (tree, node->left(NOW)); if (left->right_child(NOW)) {