Make a g_tree_node_free() function to avoid code duplication. Use g_atomic_ function...
authorDana Jansens <danakj@orodu.net>
Thu, 12 Nov 2009 14:40:31 +0000 (09:40 -0500)
committerDana Jansens <danakj@orodu.net>
Thu, 12 Nov 2009 22:21:09 +0000 (17:21 -0500)
glib/gtree.c

index 858e93169685fda31b3dc9aff91780280ab5e12a..5ea56fde9dc54d9987dd1f274033681d5449b2d3 100644 (file)
@@ -84,7 +84,7 @@ struct _GTreeNodeData
 {
   gpointer   key;         /* key for this node */
   gpointer   value;       /* value stored at this node */
-  guint16    ref_count;
+  gint       ref_count;
   guint8     stolen;      /* true if the node is stolen instead of removed */
 };
 
@@ -171,6 +171,38 @@ g_tree_node_new (GTree   *tree,
   return node;
 }
 
+static gboolean
+g_tree_node_free (GTree     *tree,
+                  GTreeNode *node)
+{
+  gboolean data_free = FALSE;
+
+  /* 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 (g_atomic_int_dec_and_test (&node->data->ref_count))
+    {
+      if (!node->data->stolen)
+        {
+          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);
+      data_free = TRUE;
+    }
+
+  g_slice_free1 (sizeof(GTreeNodeVersion) *
+                 (node->version(NOW) == 0 ? 1 : TABLE_SIZE),
+                 node->v);
+  node->v = NULL;
+  node->data = NULL;
+  g_slice_free (GTreeNode, node);
+
+  return data_free;
+}
+
 /**
  * g_tree_new:
  * @key_compare_func: the function used to order the nodes in the #GTree.
@@ -397,37 +429,15 @@ g_tree_node_next (GTreeNode *node,
 }
 
 static inline void
-g_tree_node_remove (GTree *tree, GTreeNode *node)
+g_tree_node_free_all (GTree *tree, GTreeNode *node)
 {
   if (!node)
     return;
 
-  g_tree_node_remove (tree, node->left(NOW));
-  g_tree_node_remove (tree, node->right(NOW));
+  g_tree_node_free_all (tree, node->left(NOW));
+  g_tree_node_free_all (tree, node->right(NOW));
 
-  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 (--node->data->ref_count == 0)
-    {
-      if (!node->data->stolen)
-        {
-          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);
-    }
-
-  g_slice_free1 (sizeof(GTreeNodeVersion) *
-                 (node->version(NOW) == 0 ? 1 : TABLE_SIZE),
-                 node->v);
-  node->v = NULL;
-  node->data = NULL;
-  g_slice_free (GTreeNode, node);
+  g_tree_node_free (tree, node);
 }
 
 static void
@@ -439,7 +449,7 @@ g_tree_remove_all (GTree *tree)
   if (tree->version > 0)
     g_tree_delete_versions (tree, tree->version-1);
 
-  g_tree_node_remove (tree, tree->root(NOW));
+  g_tree_node_free_all (tree, tree->root(NOW));
 
   tree->roots[0].root = NULL;
   tree->roots[0].version = tree->version = 0;
@@ -635,24 +645,7 @@ g_tree_node_delete_versions (GTree     *tree,
   /* if we removed the last version inside the node, then we can free it */
   if (node->nv == 0)
     {
-      if (--node->data->ref_count == 0)
-        {
-          if (!node->data->stolen)
-            {
-              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);
-        }
-
-      g_slice_free1 (sizeof(GTreeNodeVersion) *
-                     (node->version(NOW) == 0 ? 1 : TABLE_SIZE),
-                     node->v);
-      node->v = NULL;
-      node->data = NULL;
-      g_slice_free (GTreeNode, node);
+      g_tree_node_free (tree, node);
       node = NULL;
     }
 
@@ -797,7 +790,7 @@ g_tree_node_add_version (GTree     *tree,
       GTreeNode *newnode = g_slice_new(GTreeNode);
       newnode->v = g_slice_alloc(sizeof(GTreeNodeVersion) * TABLE_SIZE);
       newnode->data = node->data;
-      newnode->data->ref_count++;
+      g_atomic_int_inc (&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;
@@ -1160,8 +1153,12 @@ g_tree_remove (GTree         *tree,
  * Removes a key and its associated value from a #GTree without calling 
  * the key and value destroy functions.  Note that if the key existed in
  * earlier versions of the tree (g_tree_next_version() has been called since
- * it was inserted), then it cannot be removed from the tree, until all
- * versions containing the node are removed from the tree.
+ * it was inserted), then it cannot be removed from the tree until all
+ * versions containing the node are removed from the tree, by calling
+ * g_tree_delete_versions().  However, if the node is removed from the current
+ * version of the tree with g_tree_steal() then the key and value destroy
+ * functions will not be called once the last version of the key/value pair
+ * is removed.
  * If the key does not exist in the #GTree, the function does nothing.
  *
  * Returns: %TRUE if the key was found and able to be removed
@@ -1196,7 +1193,7 @@ g_tree_remove_internal (GTree         *tree,
 {
   GTreeNode *node, *parent;
   gboolean is_leftchild;
-  gboolean key_removed = FALSE;
+  gboolean data_free;
 
   g_return_val_if_fail (tree != NULL, FALSE);
 
@@ -1325,38 +1322,15 @@ g_tree_remove_internal (GTree         *tree,
       --node->nv;
     }
 
+  node->data->stolen = steal;
+  data_free = FALSE;
+
   /* only really delete the node if it was only in the current version,
      otherwise it needs to be remembered */
   if (node->nv == 0)
-    {
-      /* 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 (!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_free1 (sizeof(GTreeNodeVersion) *
-                     (node->version(NOW) == 0 ? 1 : TABLE_SIZE),
-                     node->v);
-      node->v = NULL;
-      node->data = NULL;
-      g_slice_free (GTreeNode, node);
-    }
-  else if (steal)
-    node->data->stolen = TRUE;
+    data_free = g_tree_node_free (tree, node);
 
-  return key_removed;
+  return data_free;
 }
 
 /**