Add g_tree_current_version() and g_tree_next_version() functions. Change the GTreeNo...
authorDana Jansens <danakj@orodu.net>
Thu, 29 Oct 2009 15:07:29 +0000 (11:07 -0400)
committerDana Jansens <danakj@orodu.net>
Thu, 12 Nov 2009 21:54:04 +0000 (16:54 -0500)
glib/gtree.c
glib/gtree.h

index 53d3df0079b7484a3da60a5f0dd5dc698277de49..ac076e85e9f05b60c8f066654f26f30a3f4cd92b 100644 (file)
 
 #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);
 }
 
 
index 45f15b6d06e933e1ffced7fb94e0c52beabe77d1..921bc57704053c7f4ba963ef1566c6730bb00e69 100644 (file)
@@ -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);