Free a node's data and return TRUE for g_tree_remove() only if it's the last version...
authorDana Jansens <danakj@orodu.net>
Sat, 31 Oct 2009 01:03:21 +0000 (21:03 -0400)
committerDana Jansens <danakj@orodu.net>
Thu, 12 Nov 2009 21:54:06 +0000 (16:54 -0500)
glib/gtree.c

index ae0755c3006caa9f49bfcd8fe76c2f966b080ebe..1a2e2e1e77300c904fc314df7e18e74792e84d68 100644 (file)
@@ -84,6 +84,7 @@ struct _GTreeNodeData
 {
   gpointer   key;         /* key for this node */
   gpointer   value;       /* value stored at this node */
+  guint      ref_count;
 };
 
 struct _GTreeNode
@@ -153,6 +154,7 @@ g_tree_node_new (GTree   *tree,
   node->data = g_slice_new(GTreeNodeData);
   node->data->key = key;
   node->data->value = value;
+  node->data->ref_count = 1;
 
   /* for the version 0, only allocate one set of pointers for a node,
      so that we don't use a lot more memory when persistence isn't even
@@ -537,6 +539,7 @@ g_tree_node_next_version (GTree     *tree,
       /* we filled the node's pointer table and need to make a new GTreeNode */
       GTreeNode *newnode = g_slice_new(GTreeNode);
       newnode->data = node->data;
+      newnode->data->ref_count++;
       newnode->v[0] = node->v[0]; /* copy the latest version to here */
       newnode->v[0].version = tree->version;
       newnode->nv = 1;
@@ -904,6 +907,7 @@ g_tree_remove_internal (GTree         *tree,
 {
   GTreeNode *node, *parent;
   gboolean is_leftchild;
+  gboolean key_removed = FALSE;
 
   g_return_val_if_fail (tree != NULL, FALSE);
 
@@ -1022,24 +1026,30 @@ g_tree_remove_internal (GTree         *tree,
      it needs to be remembered */
   if (node->nv == 1 && node->version(NOW) == tree->version)
     {
-      if (!steal)
+      /* free the node's data if it's the last node which is using it. just
+         because the version of the node was created in the latest version 
+         of the tree, doesn't mean there aren't older versions around still */
+      if (--node->data->ref_count == 0)
         {
-          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 (GTreeNodeData, node->data);
+
+          key_removed = TRUE;
         }
 
-      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);
-
-      return TRUE;
     }
 
-  return FALSE;
+  return key_removed;
 }
 
 /**