{
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 */
};
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.
}
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
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;
/* 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;
}
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;
* 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
{
GTreeNode *node, *parent;
gboolean is_leftchild;
- gboolean key_removed = FALSE;
+ gboolean data_free;
g_return_val_if_fail (tree != NULL, FALSE);
--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;
}
/**