updated
[platform/upstream/glib.git] / gtree.c
diff --git a/gtree.c b/gtree.c
index c2f97de..3cb7e1a 100644 (file)
--- a/gtree.c
+++ b/gtree.c
@@ -2,23 +2,23 @@
  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 /*
- * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GLib Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
  * MT safe
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include "glib.h"
 
 
@@ -37,7 +41,8 @@ typedef struct _GTreeNode  GTreeNode;
 struct _GRealTree
 {
   GTreeNode *root;
-  GCompareFunc key_compare;
+  GCompareDataFunc key_compare;
+  gpointer key_compare_data;
 };
 
 struct _GTreeNode
@@ -54,13 +59,15 @@ static GTreeNode* g_tree_node_new                   (gpointer        key,
                                                     gpointer        value);
 static void       g_tree_node_destroy               (GTreeNode      *node);
 static GTreeNode* g_tree_node_insert                (GTreeNode      *node,
-                                                    GCompareFunc    compare,
+                                                    GCompareDataFunc compare,
+                                                    gpointer        comp_data,
                                                     gpointer        key,
                                                     gpointer        value,
                                                     gint           *inserted);
 static GTreeNode* g_tree_node_remove                (GTreeNode      *node,
-                                                    GCompareFunc    compare,
-                                                    gpointer        key);
+                                                    GCompareDataFunc compare,
+                                                    gpointer        comp_data,
+                                                    gconstpointer   key);
 static GTreeNode* g_tree_node_balance               (GTreeNode      *node);
 static GTreeNode* g_tree_node_remove_leftmost       (GTreeNode      *node,
                                                     GTreeNode     **leftmost);
@@ -68,9 +75,10 @@ static GTreeNode* g_tree_node_restore_left_balance  (GTreeNode      *node,
                                                     gint            old_balance);
 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode      *node,
                                                     gint            old_balance);
-static gpointer   g_tree_node_lookup                (GTreeNode      *node,
-                                                    GCompareFunc    compare,
-                                                    gpointer        key);
+static GTreeNode* g_tree_node_lookup                (GTreeNode      *node,
+                                                    GCompareDataFunc compare,
+                                                    gpointer        comp_data,
+                                                    gconstpointer   key);
 static gint       g_tree_node_count                 (GTreeNode      *node);
 static gint       g_tree_node_pre_order             (GTreeNode      *node,
                                                     GTraverseFunc   traverse_func,
@@ -82,8 +90,8 @@ static gint       g_tree_node_post_order            (GTreeNode      *node,
                                                     GTraverseFunc   traverse_func,
                                                     gpointer        data);
 static gpointer   g_tree_node_search                (GTreeNode      *node,
-                                                    GSearchFunc     search_func,
-                                                    gpointer        data);
+                                                    GCompareFunc    search_func,
+                                                    gconstpointer   data);
 static gint       g_tree_node_height                (GTreeNode      *node);
 static GTreeNode* g_tree_node_rotate_left           (GTreeNode      *node);
 static GTreeNode* g_tree_node_rotate_right          (GTreeNode      *node);
@@ -149,9 +157,8 @@ g_tree_node_destroy (GTreeNode *node)
    }
 }
 
-
-GTree*
-g_tree_new (GCompareFunc key_compare_func)
+GTree*  g_tree_new_udata(GCompareDataFunc key_compare_func,
+                          gpointer        key_compare_data)
 {
   GRealTree *rtree;
 
@@ -160,10 +167,18 @@ g_tree_new (GCompareFunc key_compare_func)
   rtree = g_new (GRealTree, 1);
   rtree->root = NULL;
   rtree->key_compare = key_compare_func;
+  rtree->key_compare_data = key_compare_data;
 
   return (GTree*) rtree;
 }
 
+GTree*
+g_tree_new (GCompareFunc key_compare_func)
+{
+  return g_tree_new_udata ((GCompareDataFunc) key_compare_func, NULL);
+}
+
+
 void
 g_tree_destroy (GTree *tree)
 {
@@ -191,12 +206,13 @@ g_tree_insert (GTree    *tree,
 
   inserted = FALSE;
   rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
+                                   rtree->key_compare_data,
                                    key, value, &inserted);
 }
 
 void
-g_tree_remove (GTree    *tree,
-              gpointer  key)
+g_tree_remove (GTree         *tree,
+              gconstpointer  key)
 {
   GRealTree *rtree;
 
@@ -204,20 +220,55 @@ g_tree_remove (GTree    *tree,
 
   rtree = (GRealTree*) tree;
 
-  rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
+  rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare,
+                                    rtree->key_compare_data, key);
 }
 
 gpointer
-g_tree_lookup (GTree    *tree,
-              gpointer  key)
+g_tree_lookup (GTree         *tree,
+              gconstpointer  key)
 {
   GRealTree *rtree;
+  GTreeNode *node;
 
   g_return_val_if_fail (tree != NULL, NULL);
 
   rtree = (GRealTree*) tree;
 
-  return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
+  node = g_tree_node_lookup (rtree->root, rtree->key_compare, 
+                             rtree->key_compare_data, key);
+
+  return node ? node->value : NULL;
+}
+
+gboolean
+g_tree_lookup_extended (GTree         *tree,
+                        gconstpointer  lookup_key,
+                        gpointer      *orig_key,
+                        gpointer      *value)
+{
+  GRealTree *rtree;
+  GTreeNode *node;
+  
+  g_return_val_if_fail (tree != NULL, FALSE);
+  
+  rtree = (GRealTree*) tree;
+  
+  node = g_tree_node_lookup (rtree->root, 
+                             rtree->key_compare,
+                             rtree->key_compare_data, 
+                             lookup_key);
+
+  if (node)
+    {
+      if (orig_key)
+        *orig_key = node->key;
+      if (value)
+        *value = node->value;
+      return TRUE;
+    }
+  else
+    return FALSE;
 }
 
 void
@@ -256,9 +307,9 @@ g_tree_traverse (GTree         *tree,
 }
 
 gpointer
-g_tree_search (GTree       *tree,
-              GSearchFunc  search_func,
-              gpointer     data)
+g_tree_search (GTree            *tree,
+              GCompareFunc      search_func,
+              gconstpointer     data)
 {
   GRealTree *rtree;
 
@@ -303,11 +354,12 @@ g_tree_nnodes (GTree *tree)
 }
 
 static GTreeNode*
-g_tree_node_insert (GTreeNode    *node,
-                   GCompareFunc  compare,
-                   gpointer      key,
-                   gpointer      value,
-                   gint         *inserted)
+g_tree_node_insert (GTreeNode      *node,
+                   GCompareDataFunc compare,
+                   gpointer        compare_data,
+                   gpointer        key,
+                   gpointer        value,
+                   gint           *inserted)
 {
   gint old_balance;
   gint cmp;
@@ -318,7 +370,7 @@ g_tree_node_insert (GTreeNode    *node,
       return g_tree_node_new (key, value);
     }
 
-  cmp = (* compare) (key, node->key);
+  cmp = (* compare) (key, node->key, compare_data);
   if (cmp == 0)
     {
       *inserted = FALSE;
@@ -331,7 +383,8 @@ g_tree_node_insert (GTreeNode    *node,
       if (node->left)
        {
          old_balance = node->left->balance;
-         node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
+         node->left = g_tree_node_insert (node->left, compare, compare_data,
+                                          key, value, inserted);
 
          if ((old_balance != node->left->balance) && node->left->balance)
            node->balance -= 1;
@@ -348,7 +401,8 @@ g_tree_node_insert (GTreeNode    *node,
       if (node->right)
        {
          old_balance = node->right->balance;
-         node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
+         node->right = g_tree_node_insert (node->right, compare, compare_data,
+                                           key, value, inserted);
 
          if ((old_balance != node->right->balance) && node->right->balance)
            node->balance += 1;
@@ -371,9 +425,10 @@ g_tree_node_insert (GTreeNode    *node,
 }
 
 static GTreeNode*
-g_tree_node_remove (GTreeNode    *node,
-                   GCompareFunc  compare,
-                   gpointer      key)
+g_tree_node_remove (GTreeNode      *node,
+                   GCompareDataFunc compare,
+                   gpointer        compare_data,
+                   gconstpointer   key)
 {
   GTreeNode *new_root;
   gint old_balance;
@@ -382,7 +437,7 @@ g_tree_node_remove (GTreeNode    *node,
   if (!node)
     return NULL;
 
-  cmp = (* compare) (key, node->key);
+  cmp = (* compare) (key, node->key, compare_data);
   if (cmp == 0)
     {
       GTreeNode *garbage;
@@ -419,7 +474,7 @@ g_tree_node_remove (GTreeNode    *node,
       if (node->left)
        {
          old_balance = node->left->balance;
-         node->left = g_tree_node_remove (node->left, compare, key);
+         node->left = g_tree_node_remove (node->left, compare, compare_data, key);
          node = g_tree_node_restore_left_balance (node, old_balance);
        }
     }
@@ -428,7 +483,7 @@ g_tree_node_remove (GTreeNode    *node,
       if (node->right)
        {
          old_balance = node->right->balance;
-         node->right = g_tree_node_remove (node->right, compare, key);
+         node->right = g_tree_node_remove (node->right, compare, compare_data, key);
          node = g_tree_node_restore_right_balance (node, old_balance);
        }
     }
@@ -502,29 +557,30 @@ g_tree_node_restore_right_balance (GTreeNode *node,
   return node;
 }
 
-static gpointer
-g_tree_node_lookup (GTreeNode    *node,
-                   GCompareFunc  compare,
-                   gpointer      key)
+static GTreeNode *
+g_tree_node_lookup (GTreeNode      *node,
+                   GCompareDataFunc compare,
+                   gpointer        compare_data,
+                   gconstpointer   key)
 {
   gint cmp;
 
   if (!node)
     return NULL;
 
-  cmp = (* compare) (key, node->key);
+  cmp = (* compare) (key, node->key, compare_data);
   if (cmp == 0)
-    return node->value;
+    return node;
 
   if (cmp < 0)
     {
       if (node->left)
-       return g_tree_node_lookup (node->left, compare, key);
+       return g_tree_node_lookup (node->left, compare, compare_data, key);
     }
   else if (cmp > 0)
     {
       if (node->right)
-       return g_tree_node_lookup (node->right, compare, key);
+       return g_tree_node_lookup (node->right, compare, compare_data, key);
     }
 
   return NULL;
@@ -608,9 +664,9 @@ g_tree_node_post_order (GTreeNode     *node,
 }
 
 static gpointer
-g_tree_node_search (GTreeNode   *node,
-                   GSearchFunc  search_func,
-                   gpointer     data)
+g_tree_node_search (GTreeNode     *node,
+                   GCompareFunc   search_func,
+                   gconstpointer  data)
 {
   gint dir;
 
@@ -626,7 +682,7 @@ g_tree_node_search (GTreeNode   *node,
       node = node->left;
     else if (dir > 0)
       node = node->right;
-  } while (node && (dir != 0));
+  } while (node);
 
   return NULL;
 }
@@ -657,12 +713,10 @@ g_tree_node_height (GTreeNode *node)
 static GTreeNode*
 g_tree_node_rotate_left (GTreeNode *node)
 {
-  GTreeNode *left;
   GTreeNode *right;
   gint a_bal;
   gint b_bal;
 
-  left = node->left;
   right = node->right;
 
   node->right = right->left;
@@ -695,12 +749,10 @@ static GTreeNode*
 g_tree_node_rotate_right (GTreeNode *node)
 {
   GTreeNode *left;
-  GTreeNode *right;
   gint a_bal;
   gint b_bal;
 
   left = node->left;
-  right = node->right;
 
   node->left = left->right;
   left->right = node;