From: Dana Jansens Date: Thu, 29 Oct 2009 15:07:29 +0000 (-0400) Subject: Add g_tree_current_version() and g_tree_next_version() functions. Change the GTreeNo... X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=22c6714e99a45be7eb6f90e1a2e8ddd51081ddb3;p=dana%2Fcg-glib.git Add g_tree_current_version() and g_tree_next_version() functions. Change the GTreeNode structure so that it can keep multiple versions of its navigation pointers. --- diff --git a/glib/gtree.c b/glib/gtree.c index 53d3df00..ac076e85 100644 --- a/glib/gtree.c +++ b/glib/gtree.c @@ -35,7 +35,12 @@ #undef G_TREE_DEBUG -typedef struct _GTreeNode GTreeNode; +#define MAX_OUT_DEGREE 3 +#define MAX_IN_DEGREE 5 + +typedef struct _GTreeNode GTreeNode; +typedef struct _GTreeNodeData GTreeNodeData; +typedef struct _GTreeNodeVersion GTreeNodeVersion; struct _GTree { @@ -46,12 +51,12 @@ struct _GTree gpointer key_compare_data; guint nnodes; gint ref_count; + guint version; }; -struct _GTreeNode +struct _GTreeNodeVersion { - gpointer key; /* key for this node */ - gpointer value; /* value stored at this node */ + guint version; GTreeNode *left; /* left subtree */ GTreeNode *right; /* right subtree */ GTreeNode *parent; /* parent node */ @@ -61,9 +66,33 @@ struct _GTreeNode the next node in the tree) */ }; +struct _GTreeNodeData +{ + gpointer key; /* key for this node */ + gpointer value; /* value stored at this node */ +}; + +struct _GTreeNode +{ + GTreeNodeData *data; /* the node's permanent data */ + GTreeNodeVersion *v; /* versions of pointers for the node, new versions + * are prepended onto the array so v[0] is the newest + */ + guint nv; /* number of versions stored in this node */ +}; + +#define NOW (0) + +#define version(i) v[i].version +#define left(i) v[i].left +#define right(i) v[i].right +#define parent(i) v[i].parent +#define left_child(i) v[i].left_child +#define right_child(i) v[i].right_child static GTreeNode* g_tree_node_new (gpointer key, - gpointer value); + gpointer value, + guint version); static guint g_tree_priority (GTreeNode *node); static void g_tree_insert_internal (GTree *tree, gpointer key, @@ -97,17 +126,28 @@ static void g_tree_node_check (GTreeNode *node); static GTreeNode* g_tree_node_new (gpointer key, - gpointer value) + gpointer value, + guint version) { GTreeNode *node = g_slice_new (GTreeNode); - node->left = NULL; - node->right = NULL; - node->parent = NULL; - node->left_child = FALSE; - node->right_child = FALSE; - node->key = key; - node->value = value; + node->data = g_slice_new(GTreeNodeData); + node->data->key = key; + node->data->value = value; + + /* 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 + being used */ + node->v = g_slice_alloc(sizeof(GTreeNodeVersion) * + (version == 0 ? 1 : MAX_IN_DEGREE + 1)); + node->nv = 1; + + node->v[0].version = version; + node->v[0].left = NULL; + node->v[0].right = NULL; + node->v[0].parent = NULL; + node->v[0].left_child = FALSE; + node->v[0].right_child = FALSE; return node; } @@ -188,6 +228,7 @@ g_tree_new_full (GCompareDataFunc key_compare_func, tree->key_compare_data = key_compare_data; tree->nnodes = 0; tree->ref_count = 1; + tree->version = 0; return tree; } @@ -202,8 +243,8 @@ g_tree_first_node (GTree *tree) tmp = tree->root; - while (tmp->left_child) - tmp = tmp->left; + while (tmp->left_child(NOW)) + tmp = tmp->left(NOW); return tmp; } @@ -213,11 +254,11 @@ g_tree_node_previous (GTreeNode *node) { GTreeNode *tmp; - tmp = node->left; + tmp = node->left(NOW); - if (node->left_child) - while (tmp->right_child) - tmp = tmp->right; + if (node->left_child(NOW)) + while (tmp->right_child(NOW)) + tmp = tmp->right(NOW); return tmp; } @@ -227,11 +268,11 @@ g_tree_node_next (GTreeNode *node) { GTreeNode *tmp; - tmp = node->right; + tmp = node->right(NOW); - if (node->right_child) - while (tmp->left_child) - tmp = tmp->left; + if (node->right_child(NOW)) + while (tmp->left_child(NOW)) + tmp = tmp->left(NOW); return tmp; } @@ -251,9 +292,9 @@ g_tree_remove_all (GTree *tree) next = g_tree_node_next (node); if (tree->key_destroy_func) - tree->key_destroy_func (node->key); + tree->key_destroy_func (node->data->key); if (tree->value_destroy_func) - tree->value_destroy_func (node->value); + tree->value_destroy_func (node->data->value); g_slice_free (GTreeNode, node); node = next; @@ -329,6 +370,36 @@ g_tree_destroy (GTree *tree) g_tree_unref (tree); } +/** + * g_tree_current_version: + * @tree: a #GTree + * + * Returns the current version number of the #GTree. Inserting or deleting + * keys will affect the current version, but not change earlier versions. + * + * Returns: the current version number of the #GTree. + **/ +guint +g_tree_current_version (GTree *tree) +{ + return tree->version; +} + +/** + * g_tree_next_version: + * @tree: a #GTree + * + * Increments the version number of the tree. Inserting or deleting keys will + * affect the new version of the tree, but not change earlier versions. + * + * Returns: the new current version number of the #GTree. + **/ +guint +g_tree_next_version (GTree *tree) +{ + return ++tree->version; +} + /** * g_tree_insert: * @tree: a #GTree. @@ -396,7 +467,7 @@ g_tree_replace (GTree *tree, static guint g_tree_priority (GTreeNode *node) { - guint key = GPOINTER_TO_UINT (node); + guint key = GPOINTER_TO_UINT (node->data); /* This hash function is based on one found on Thomas Wang's * web page at @@ -428,7 +499,7 @@ g_tree_insert_internal (GTree *tree, if (!tree->root) { - tree->root = g_tree_node_new (key, value); + tree->root = g_tree_node_new (key, value, tree->version); tree->nnodes++; return; } @@ -437,21 +508,22 @@ g_tree_insert_internal (GTree *tree, while (1) { - gint cmp = tree->key_compare (key, node->key, tree->key_compare_data); + gint cmp = tree->key_compare (key, node->data->key, + tree->key_compare_data); if (cmp == 0) { if (tree->value_destroy_func) - tree->value_destroy_func (node->value); + tree->value_destroy_func (node->data->value); - node->value = value; + node->data->value = value; if (replace) { if (tree->key_destroy_func) - tree->key_destroy_func (node->key); + tree->key_destroy_func (node->data->key); - node->key = key; + node->data->key = key; } else { @@ -464,18 +536,18 @@ g_tree_insert_internal (GTree *tree, } else if (cmp < 0) { - if (node->left_child) - node = node->left; + if (node->left_child(NOW)) + node = node->left(NOW); else { - child = g_tree_node_new (key, value); + child = g_tree_node_new (key, value, tree->version); - child->left = node->left; - child->right = node; - child->parent = node; + child->v[0].left = node->v[0].left; + child->v[0].right = node; + child->v[0].parent = node; - node->left = child; - node->left_child = TRUE; + node->v[0].left = child; + node->v[0].left_child = TRUE; tree->nnodes++; @@ -484,18 +556,18 @@ g_tree_insert_internal (GTree *tree, } else { - if (node->right_child) - node = node->right; + if (node->right_child(NOW)) + node = node->right(NOW); else { - child = g_tree_node_new (key, value); + child = g_tree_node_new (key, value, tree->version); - child->right = node->right; - child->left = node; - child->parent = node; + child->v[0].right = node->v[0].right; + child->v[0].left = node; + child->v[0].parent = node; - node->right = child; - node->right_child = TRUE; + node->v[0].right = child; + node->v[0].right_child = TRUE; tree->nnodes++; @@ -506,22 +578,22 @@ g_tree_insert_internal (GTree *tree, /* rotate the new node up until the heap property is restored */ node = child; - while (node->parent && - g_tree_priority (node) < g_tree_priority (node->parent)) + while (node->parent(NOW) && + g_tree_priority (node) < g_tree_priority (node->parent(NOW))) { - GTreeNode *const sp = node->parent->parent; - GTreeNode *const p = node->parent; - if (p->left == node) + GTreeNode *const sp = node->parent(NOW)->parent(NOW); + GTreeNode *const p = node->parent(NOW); + if (p->left(NOW) == node) g_tree_node_rotate_right (p); else g_tree_node_rotate_left (p); if (!sp) tree->root = node; - else if (sp->left == p) - sp->left = node; + else if (sp->left(NOW) == p) + sp->left(NOW) = node; else - sp->right = node; + sp->right(NOW) = node; } } @@ -607,44 +679,46 @@ g_tree_remove_internal (GTree *tree, while (1) { - gint cmp = tree->key_compare (key, node->key, tree->key_compare_data); + gint cmp = tree->key_compare (key, node->data->key, + tree->key_compare_data); if (cmp == 0) break; else if (cmp < 0) { - if (!node->left_child) + if (!node->left_child(NOW)) return FALSE; parent = node; is_leftchild = TRUE; - node = node->left; + node = node->left(NOW); } else { - if (!node->right_child) + if (!node->right_child(NOW)) return FALSE; parent = node; is_leftchild = FALSE; - node = node->right; + node = node->right(NOW); } } /* rotate the node down the tree, maintaining the heap property */ - while (node->left_child || node->right_child) + while (node->left_child(NOW) || node->right_child(NOW)) { - if (!node->left_child || - (node->right_child && - g_tree_priority (node->left) > g_tree_priority (node->right))) + if (!node->left_child(NOW) || + (node->right_child(NOW) && + g_tree_priority (node->left(NOW)) > + g_tree_priority (node->right(NOW)))) { /* rotate the right child up */ if (!parent) parent = tree->root = g_tree_node_rotate_left (node); else if (is_leftchild) - parent = parent->left = g_tree_node_rotate_left (node); + parent = parent->v[0].left = g_tree_node_rotate_left (node); else - parent = parent->right = g_tree_node_rotate_left (node); + parent = parent->v[0].right = g_tree_node_rotate_left (node); is_leftchild = TRUE; } else @@ -653,9 +727,9 @@ g_tree_remove_internal (GTree *tree, if (!parent) parent = tree->root = g_tree_node_rotate_right (node); else if (is_leftchild) - parent = parent->left = g_tree_node_rotate_right (node); + parent = parent->v[0].left = g_tree_node_rotate_right (node); else - parent = parent->right = g_tree_node_rotate_right (node); + parent = parent->v[0].right = g_tree_node_rotate_right (node); is_leftchild = FALSE; } } @@ -665,21 +739,21 @@ g_tree_remove_internal (GTree *tree, tree->root = NULL; else if (is_leftchild) { - parent->left_child = FALSE; - parent->left = node->left; + parent->v[0].left_child = FALSE; + parent->v[0].left = node->v[0].left; } else { - parent->right_child = FALSE; - parent->right = node->right; + parent->v[0].right_child = FALSE; + parent->v[0].right = node->v[0].right; } if (!steal) { if (tree->key_destroy_func) - tree->key_destroy_func (node->key); + tree->key_destroy_func (node->data->key); if (tree->value_destroy_func) - tree->value_destroy_func (node->value); + tree->value_destroy_func (node->data->value); } g_slice_free (GTreeNode, node); @@ -746,7 +820,7 @@ g_tree_lookup_related (GTree *tree, node = g_tree_find_node (tree, key, search_type); - return node ? node->value : NULL; + return node ? node->data->value : NULL; } /** @@ -778,9 +852,9 @@ g_tree_lookup_extended (GTree *tree, if (node) { if (orig_key) - *orig_key = node->key; + *orig_key = node->data->key; if (value) - *value = node->value; + *value = node->data->value; return TRUE; } else @@ -819,7 +893,7 @@ g_tree_foreach (GTree *tree, while (node) { - if ((*func) (node->key, node->value, user_data)) + if ((*func) (node->data->key, node->data->value, user_data)) break; node = g_tree_node_next (node); @@ -948,8 +1022,8 @@ g_tree_node_height(GTreeNode *node) { gint l = 0, r = 0; if (node == NULL) return 0; - if (node->left_child) l = g_tree_node_height (node->left); - if (node->right_child) r = g_tree_node_height (node->right); + if (node->left_child(NOW)) l = g_tree_node_height (node->left(NOW)); + if (node->right_child(NOW)) r = g_tree_node_height (node->right(NOW)); return 1 + MAX(l, r); } @@ -1004,26 +1078,26 @@ g_tree_find_node (GTree *tree, remember = NULL; while (1) { - cmp = tree->key_compare (key, node->key, tree->key_compare_data); + cmp = tree->key_compare (key, node->data->key, tree->key_compare_data); if (cmp == 0) return node; else if (cmp < 0) { if (search_type == G_TREE_SEARCH_SUCCESSOR) remember = node; - if (!node->left_child) + if (!node->left_child(NOW)) return remember; - node = node->left; + node = node->left(NOW); } else { if (search_type == G_TREE_SEARCH_PREDECESSOR) remember = node; - if (!node->right_child) + if (!node->right_child(NOW)) return remember; - node = node->right; + node = node->right(NOW); } } } @@ -1033,18 +1107,18 @@ g_tree_node_pre_order (GTreeNode *node, GTraverseFunc traverse_func, gpointer data) { - if ((*traverse_func) (node->key, node->value, data)) + if ((*traverse_func) (node->data->key, node->data->value, data)) return TRUE; - if (node->left_child) + if (node->left_child(NOW)) { - if (g_tree_node_pre_order (node->left, traverse_func, data)) + if (g_tree_node_pre_order (node->left(NOW), traverse_func, data)) return TRUE; } - if (node->right_child) + if (node->right_child(NOW)) { - if (g_tree_node_pre_order (node->right, traverse_func, data)) + if (g_tree_node_pre_order (node->right(NOW), traverse_func, data)) return TRUE; } @@ -1056,18 +1130,18 @@ g_tree_node_in_order (GTreeNode *node, GTraverseFunc traverse_func, gpointer data) { - if (node->left_child) + if (node->left_child(NOW)) { - if (g_tree_node_in_order (node->left, traverse_func, data)) + if (g_tree_node_in_order (node->left(NOW), traverse_func, data)) return TRUE; } - if ((*traverse_func) (node->key, node->value, data)) + if ((*traverse_func) (node->data->key, node->data->value, data)) return TRUE; - if (node->right_child) + if (node->right_child(NOW)) { - if (g_tree_node_in_order (node->right, traverse_func, data)) + if (g_tree_node_in_order (node->right(NOW), traverse_func, data)) return TRUE; } @@ -1079,19 +1153,19 @@ g_tree_node_post_order (GTreeNode *node, GTraverseFunc traverse_func, gpointer data) { - if (node->left_child) + if (node->left_child(NOW)) { - if (g_tree_node_post_order (node->left, traverse_func, data)) + if (g_tree_node_post_order (node->left(NOW), traverse_func, data)) return TRUE; } - if (node->right_child) + if (node->right_child(NOW)) { - if (g_tree_node_post_order (node->right, traverse_func, data)) + if (g_tree_node_post_order (node->right(NOW), traverse_func, data)) return TRUE; } - if ((*traverse_func) (node->key, node->value, data)) + if ((*traverse_func) (node->data->key, node->data->value, data)) return TRUE; return FALSE; @@ -1112,26 +1186,26 @@ g_tree_node_search (GTreeNode *node, remember = NULL; while (1) { - dir = (* search_func) (node->key, data); + dir = (* search_func) (node->data->key, data); if (dir == 0) - return node->value; + return node->data->value; else if (dir < 0) { if (search_type == G_TREE_SEARCH_SUCCESSOR) remember = node; - if (!node->left_child) + if (!node->left_child(NOW)) return remember; - node = node->left; + node = node->left(NOW); } else { if (search_type == G_TREE_SEARCH_PREDECESSOR) remember = node; - if (!node->right_child) + if (!node->right_child(NOW)) return remember; - node = node->right; + node = node->right(NOW); } } } @@ -1141,22 +1215,22 @@ g_tree_node_rotate_left (GTreeNode *node) { GTreeNode *right; - right = node->right; + right = node->v[0].right; - if (right->left_child) + if (right->v[0].left_child) { - node->right = right->left; - node->right->parent = node; + node->v[0].right = right->v[0].left; + node->v[0].right->v[0].parent = node; } else { - node->right_child = FALSE; - node->right = right; - right->left_child = TRUE; + node->v[0].right_child = FALSE; + node->v[0].right = right; + right->v[0].left_child = TRUE; } - right->left = node; - right->parent = node->parent; - node->parent = right; + right->v[0].left = node; + right->v[0].parent = node->v[0].parent; + node->v[0].parent = right; return right; } @@ -1166,22 +1240,22 @@ g_tree_node_rotate_right (GTreeNode *node) { GTreeNode *left; - left = node->left; + left = node->v[0].left; - if (left->right_child) + if (left->v[0].right_child) { - node->left = left->right; - node->left->parent = node; + node->v[0].left = left->v[0].right; + node->v[0].left->v[0].parent = node; } else { - node->left_child = FALSE; - node->left = left; - left->right_child = TRUE; + node->v[0].left_child = FALSE; + node->v[0].left = left; + left->v[0].right_child = TRUE; } - left->right = node; - left->parent = node->parent; - node->parent = left; + left->v[0].right = node; + left->v[0].parent = node->v[0].parent; + node->v[0].parent = left; return left; } @@ -1227,17 +1301,17 @@ static void g_tree_node_dump (GTreeNode *node, gint indent) { - g_print ("%*s%c\n", indent, "", *(char *)node->key); + g_print ("%*s%c\n", indent, "", *(char *)node->data->key); if (node->left_child) g_tree_node_dump (node->left, indent + 2); else if (node->left) - g_print ("%*s<%c\n", indent + 2, "", *(char *)node->left->key); + g_print ("%*s<%c\n", indent + 2, "", *(char *)node->left->data->key); if (node->right_child) g_tree_node_dump (node->right, indent + 2); else if (node->right) - g_print ("%*s>%c\n", indent + 2, "", *(char *)node->right->key); + g_print ("%*s>%c\n", indent + 2, "", *(char *)node->right->data->key); } diff --git a/glib/gtree.h b/glib/gtree.h index 45f15b6d..921bc577 100644 --- a/glib/gtree.h +++ b/glib/gtree.h @@ -61,6 +61,8 @@ GTree* g_tree_new_full (GCompareDataFunc key_compare_func, GTree* g_tree_ref (GTree *tree); void g_tree_unref (GTree *tree); void g_tree_destroy (GTree *tree); +guint g_tree_current_version (GTree *tree); +guint g_tree_next_version (GTree *tree); void g_tree_insert (GTree *tree, gpointer key, gpointer value);