Blame glib/gtree.c

Packit ae235b
/* GLIB - Library of useful routines for C programming
Packit ae235b
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General Public
Packit ae235b
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 */
Packit ae235b
Packit ae235b
/*
Packit ae235b
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
Packit ae235b
 * file for a list of people on the GLib Team.  See the ChangeLog
Packit ae235b
 * files for a list of changes.  These files are distributed with
Packit ae235b
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
Packit ae235b
 */
Packit ae235b
Packit ae235b
/* 
Packit ae235b
 * MT safe
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include "gtree.h"
Packit ae235b
Packit ae235b
#include "gatomic.h"
Packit ae235b
#include "gtestutils.h"
Packit ae235b
#include "gslice.h"
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * SECTION:trees-binary
Packit ae235b
 * @title: Balanced Binary Trees
Packit ae235b
 * @short_description: a sorted collection of key/value pairs optimized
Packit ae235b
 *                     for searching and traversing in order
Packit ae235b
 *
Packit ae235b
 * The #GTree structure and its associated functions provide a sorted
Packit ae235b
 * collection of key/value pairs optimized for searching and traversing
Packit ae235b
 * in order.
Packit ae235b
 *
Packit ae235b
 * To create a new #GTree use g_tree_new().
Packit ae235b
 *
Packit ae235b
 * To insert a key/value pair into a #GTree use g_tree_insert().
Packit ae235b
 *
Packit ae235b
 * To lookup the value corresponding to a given key, use
Packit ae235b
 * g_tree_lookup() and g_tree_lookup_extended().
Packit ae235b
 *
Packit ae235b
 * To find out the number of nodes in a #GTree, use g_tree_nnodes(). To
Packit ae235b
 * get the height of a #GTree, use g_tree_height().
Packit ae235b
 *
Packit ae235b
 * To traverse a #GTree, calling a function for each node visited in
Packit ae235b
 * the traversal, use g_tree_foreach().
Packit ae235b
 *
Packit ae235b
 * To remove a key/value pair use g_tree_remove().
Packit ae235b
 *
Packit ae235b
 * To destroy a #GTree, use g_tree_destroy().
Packit ae235b
 **/
Packit ae235b
Packit ae235b
#undef G_TREE_DEBUG
Packit ae235b
Packit ae235b
#define MAX_GTREE_HEIGHT 40
Packit ae235b
Packit ae235b
typedef struct _GTreeNode  GTreeNode;
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * GTree:
Packit ae235b
 *
Packit ae235b
 * The GTree struct is an opaque data structure representing a
Packit ae235b
 * [balanced binary tree][glib-Balanced-Binary-Trees]. It should be
Packit ae235b
 * accessed only by using the following functions.
Packit ae235b
 */
Packit ae235b
struct _GTree
Packit ae235b
{
Packit ae235b
  GTreeNode        *root;
Packit ae235b
  GCompareDataFunc  key_compare;
Packit ae235b
  GDestroyNotify    key_destroy_func;
Packit ae235b
  GDestroyNotify    value_destroy_func;
Packit ae235b
  gpointer          key_compare_data;
Packit ae235b
  guint             nnodes;
Packit ae235b
  gint              ref_count;
Packit ae235b
};
Packit ae235b
Packit ae235b
struct _GTreeNode
Packit ae235b
{
Packit ae235b
  gpointer   key;         /* key for this node */
Packit ae235b
  gpointer   value;       /* value stored at this node */
Packit ae235b
  GTreeNode *left;        /* left subtree */
Packit ae235b
  GTreeNode *right;       /* right subtree */
Packit ae235b
  gint8      balance;     /* height (right) - height (left) */
Packit ae235b
  guint8     left_child;
Packit ae235b
  guint8     right_child;
Packit ae235b
};
Packit ae235b
Packit ae235b
Packit ae235b
static GTreeNode* g_tree_node_new                   (gpointer       key,
Packit ae235b
                                                     gpointer       value);
Packit ae235b
static void       g_tree_insert_internal            (GTree         *tree,
Packit ae235b
                                                     gpointer       key,
Packit ae235b
                                                     gpointer       value,
Packit ae235b
                                                     gboolean       replace);
Packit ae235b
static gboolean   g_tree_remove_internal            (GTree         *tree,
Packit ae235b
                                                     gconstpointer  key,
Packit ae235b
                                                     gboolean       steal);
Packit ae235b
static GTreeNode* g_tree_node_balance               (GTreeNode     *node);
Packit ae235b
static GTreeNode *g_tree_find_node                  (GTree         *tree,
Packit ae235b
                                                     gconstpointer  key);
Packit ae235b
static gint       g_tree_node_pre_order             (GTreeNode     *node,
Packit ae235b
                                                     GTraverseFunc  traverse_func,
Packit ae235b
                                                     gpointer       data);
Packit ae235b
static gint       g_tree_node_in_order              (GTreeNode     *node,
Packit ae235b
                                                     GTraverseFunc  traverse_func,
Packit ae235b
                                                     gpointer       data);
Packit ae235b
static gint       g_tree_node_post_order            (GTreeNode     *node,
Packit ae235b
                                                     GTraverseFunc  traverse_func,
Packit ae235b
                                                     gpointer       data);
Packit ae235b
static gpointer   g_tree_node_search                (GTreeNode     *node,
Packit ae235b
                                                     GCompareFunc   search_func,
Packit ae235b
                                                     gconstpointer  data);
Packit ae235b
static GTreeNode* g_tree_node_rotate_left           (GTreeNode     *node);
Packit ae235b
static GTreeNode* g_tree_node_rotate_right          (GTreeNode     *node);
Packit ae235b
#ifdef G_TREE_DEBUG
Packit ae235b
static void       g_tree_node_check                 (GTreeNode     *node);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
Packit ae235b
static GTreeNode*
Packit ae235b
g_tree_node_new (gpointer key,
Packit ae235b
                 gpointer value)
Packit ae235b
{
Packit ae235b
  GTreeNode *node = g_slice_new (GTreeNode);
Packit ae235b
Packit ae235b
  node->balance = 0;
Packit ae235b
  node->left = NULL;
Packit ae235b
  node->right = NULL;
Packit ae235b
  node->left_child = FALSE;
Packit ae235b
  node->right_child = FALSE;
Packit ae235b
  node->key = key;
Packit ae235b
  node->value = value;
Packit ae235b
Packit ae235b
  return node;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_new:
Packit ae235b
 * @key_compare_func: the function used to order the nodes in the #GTree.
Packit ae235b
 *   It should return values similar to the standard strcmp() function -
Packit ae235b
 *   0 if the two arguments are equal, a negative value if the first argument 
Packit ae235b
 *   comes before the second, or a positive value if the first argument comes 
Packit ae235b
 *   after the second.
Packit ae235b
 * 
Packit ae235b
 * Creates a new #GTree.
Packit ae235b
 * 
Packit ae235b
 * Returns: a newly allocated #GTree
Packit ae235b
 */
Packit ae235b
GTree *
Packit ae235b
g_tree_new (GCompareFunc key_compare_func)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (key_compare_func != NULL, NULL);
Packit ae235b
Packit ae235b
  return g_tree_new_full ((GCompareDataFunc) key_compare_func, NULL,
Packit ae235b
                          NULL, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_new_with_data:
Packit ae235b
 * @key_compare_func: qsort()-style comparison function
Packit ae235b
 * @key_compare_data: data to pass to comparison function
Packit ae235b
 * 
Packit ae235b
 * Creates a new #GTree with a comparison function that accepts user data.
Packit ae235b
 * See g_tree_new() for more details.
Packit ae235b
 * 
Packit ae235b
 * Returns: a newly allocated #GTree
Packit ae235b
 */
Packit ae235b
GTree *
Packit ae235b
g_tree_new_with_data (GCompareDataFunc key_compare_func,
Packit ae235b
                      gpointer         key_compare_data)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (key_compare_func != NULL, NULL);
Packit ae235b
  
Packit ae235b
  return g_tree_new_full (key_compare_func, key_compare_data, 
Packit ae235b
                          NULL, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_new_full:
Packit ae235b
 * @key_compare_func: qsort()-style comparison function
Packit ae235b
 * @key_compare_data: data to pass to comparison function
Packit ae235b
 * @key_destroy_func: a function to free the memory allocated for the key 
Packit ae235b
 *   used when removing the entry from the #GTree or %NULL if you don't
Packit ae235b
 *   want to supply such a function
Packit ae235b
 * @value_destroy_func: a function to free the memory allocated for the 
Packit ae235b
 *   value used when removing the entry from the #GTree or %NULL if you 
Packit ae235b
 *   don't want to supply such a function
Packit ae235b
 * 
Packit ae235b
 * Creates a new #GTree like g_tree_new() and allows to specify functions 
Packit ae235b
 * to free the memory allocated for the key and value that get called when 
Packit ae235b
 * removing the entry from the #GTree.
Packit ae235b
 * 
Packit ae235b
 * Returns: a newly allocated #GTree
Packit ae235b
 */
Packit ae235b
GTree *
Packit ae235b
g_tree_new_full (GCompareDataFunc key_compare_func,
Packit ae235b
                 gpointer         key_compare_data,
Packit ae235b
                 GDestroyNotify   key_destroy_func,
Packit ae235b
                 GDestroyNotify   value_destroy_func)
Packit ae235b
{
Packit ae235b
  GTree *tree;
Packit ae235b
  
Packit ae235b
  g_return_val_if_fail (key_compare_func != NULL, NULL);
Packit ae235b
  
Packit ae235b
  tree = g_slice_new (GTree);
Packit ae235b
  tree->root               = NULL;
Packit ae235b
  tree->key_compare        = key_compare_func;
Packit ae235b
  tree->key_destroy_func   = key_destroy_func;
Packit ae235b
  tree->value_destroy_func = value_destroy_func;
Packit ae235b
  tree->key_compare_data   = key_compare_data;
Packit ae235b
  tree->nnodes             = 0;
Packit ae235b
  tree->ref_count          = 1;
Packit ae235b
  
Packit ae235b
  return tree;
Packit ae235b
}
Packit ae235b
Packit ae235b
static inline GTreeNode *
Packit ae235b
g_tree_first_node (GTree *tree)
Packit ae235b
{
Packit ae235b
  GTreeNode *tmp;
Packit ae235b
Packit ae235b
  if (!tree->root)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  tmp = tree->root;
Packit ae235b
Packit ae235b
  while (tmp->left_child)
Packit ae235b
    tmp = tmp->left;
Packit ae235b
Packit ae235b
  return tmp;
Packit ae235b
} 
Packit ae235b
Packit ae235b
static inline GTreeNode *
Packit ae235b
g_tree_node_previous (GTreeNode *node)
Packit ae235b
{
Packit ae235b
  GTreeNode *tmp;
Packit ae235b
Packit ae235b
  tmp = node->left;
Packit ae235b
Packit ae235b
  if (node->left_child)
Packit ae235b
    while (tmp->right_child)
Packit ae235b
      tmp = tmp->right;
Packit ae235b
Packit ae235b
  return tmp;
Packit ae235b
}
Packit ae235b
Packit ae235b
static inline GTreeNode *
Packit ae235b
g_tree_node_next (GTreeNode *node)
Packit ae235b
{
Packit ae235b
  GTreeNode *tmp;
Packit ae235b
Packit ae235b
  tmp = node->right;
Packit ae235b
Packit ae235b
  if (node->right_child)
Packit ae235b
    while (tmp->left_child)
Packit ae235b
      tmp = tmp->left;
Packit ae235b
Packit ae235b
  return tmp;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_tree_remove_all (GTree *tree)
Packit ae235b
{
Packit ae235b
  GTreeNode *node;
Packit ae235b
  GTreeNode *next;
Packit ae235b
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
Packit ae235b
  node = g_tree_first_node (tree);
Packit ae235b
Packit ae235b
  while (node)
Packit ae235b
    {
Packit ae235b
      next = g_tree_node_next (node);
Packit ae235b
Packit ae235b
      if (tree->key_destroy_func)
Packit ae235b
        tree->key_destroy_func (node->key);
Packit ae235b
      if (tree->value_destroy_func)
Packit ae235b
        tree->value_destroy_func (node->value);
Packit ae235b
      g_slice_free (GTreeNode, node);
Packit ae235b
Packit ae235b
      node = next;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  tree->root = NULL;
Packit ae235b
  tree->nnodes = 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_ref:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 *
Packit ae235b
 * Increments the reference count of @tree by one.
Packit ae235b
 *
Packit ae235b
 * It is safe to call this function from any thread.
Packit ae235b
 *
Packit ae235b
 * Returns: the passed in #GTree
Packit ae235b
 *
Packit ae235b
 * Since: 2.22
Packit ae235b
 */
Packit ae235b
GTree *
Packit ae235b
g_tree_ref (GTree *tree)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (tree != NULL, NULL);
Packit ae235b
Packit ae235b
  g_atomic_int_inc (&tree->ref_count);
Packit ae235b
Packit ae235b
  return tree;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_unref:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 *
Packit ae235b
 * Decrements the reference count of @tree by one.
Packit ae235b
 * If the reference count drops to 0, all keys and values will
Packit ae235b
 * be destroyed (if destroy functions were specified) and all
Packit ae235b
 * memory allocated by @tree will be released.
Packit ae235b
 *
Packit ae235b
 * It is safe to call this function from any thread.
Packit ae235b
 *
Packit ae235b
 * Since: 2.22
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_tree_unref (GTree *tree)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
Packit ae235b
  if (g_atomic_int_dec_and_test (&tree->ref_count))
Packit ae235b
    {
Packit ae235b
      g_tree_remove_all (tree);
Packit ae235b
      g_slice_free (GTree, tree);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_destroy:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * 
Packit ae235b
 * Removes all keys and values from the #GTree and decreases its
Packit ae235b
 * reference count by one. If keys and/or values are dynamically
Packit ae235b
 * allocated, you should either free them first or create the #GTree
Packit ae235b
 * using g_tree_new_full(). In the latter case the destroy functions
Packit ae235b
 * you supplied will be called on all keys and values before destroying
Packit ae235b
 * the #GTree.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_tree_destroy (GTree *tree)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
Packit ae235b
  g_tree_remove_all (tree);
Packit ae235b
  g_tree_unref (tree);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_insert:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @key: the key to insert
Packit ae235b
 * @value: the value corresponding to the key
Packit ae235b
 * 
Packit ae235b
 * Inserts a key/value pair into a #GTree.
Packit ae235b
 *
Packit ae235b
 * If the given key already exists in the #GTree its corresponding value
Packit ae235b
 * is set to the new value. If you supplied a @value_destroy_func when
Packit ae235b
 * creating the #GTree, the old value is freed using that function. If
Packit ae235b
 * you supplied a @key_destroy_func when creating the #GTree, the passed
Packit ae235b
 * key is freed using that function.
Packit ae235b
 *
Packit ae235b
 * The tree is automatically 'balanced' as new key/value pairs are added,
Packit ae235b
 * so that the distance from the root to every leaf is as small as possible.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_tree_insert (GTree    *tree,
Packit ae235b
               gpointer  key,
Packit ae235b
               gpointer  value)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
Packit ae235b
  g_tree_insert_internal (tree, key, value, FALSE);
Packit ae235b
Packit ae235b
#ifdef G_TREE_DEBUG
Packit ae235b
  g_tree_node_check (tree->root);
Packit ae235b
#endif
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_replace:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @key: the key to insert
Packit ae235b
 * @value: the value corresponding to the key
Packit ae235b
 * 
Packit ae235b
 * Inserts a new key and value into a #GTree similar to g_tree_insert().
Packit ae235b
 * The difference is that if the key already exists in the #GTree, it gets 
Packit ae235b
 * replaced by the new key. If you supplied a @value_destroy_func when 
Packit ae235b
 * creating the #GTree, the old value is freed using that function. If you 
Packit ae235b
 * supplied a @key_destroy_func when creating the #GTree, the old key is 
Packit ae235b
 * freed using that function. 
Packit ae235b
 *
Packit ae235b
 * The tree is automatically 'balanced' as new key/value pairs are added,
Packit ae235b
 * so that the distance from the root to every leaf is as small as possible.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_tree_replace (GTree    *tree,
Packit ae235b
                gpointer  key,
Packit ae235b
                gpointer  value)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
Packit ae235b
  g_tree_insert_internal (tree, key, value, TRUE);
Packit ae235b
Packit ae235b
#ifdef G_TREE_DEBUG
Packit ae235b
  g_tree_node_check (tree->root);
Packit ae235b
#endif
Packit ae235b
}
Packit ae235b
Packit ae235b
/* internal insert routine */
Packit ae235b
static void
Packit ae235b
g_tree_insert_internal (GTree    *tree,
Packit ae235b
                        gpointer  key,
Packit ae235b
                        gpointer  value,
Packit ae235b
                        gboolean  replace)
Packit ae235b
{
Packit ae235b
  GTreeNode *node;
Packit ae235b
  GTreeNode *path[MAX_GTREE_HEIGHT];
Packit ae235b
  int idx;
Packit ae235b
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
Packit ae235b
  if (!tree->root)
Packit ae235b
    {
Packit ae235b
      tree->root = g_tree_node_new (key, value);
Packit ae235b
      tree->nnodes++;
Packit ae235b
      return;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  idx = 0;
Packit ae235b
  path[idx++] = NULL;
Packit ae235b
  node = tree->root;
Packit ae235b
Packit ae235b
  while (1)
Packit ae235b
    {
Packit ae235b
      int cmp = tree->key_compare (key, node->key, tree->key_compare_data);
Packit ae235b
      
Packit ae235b
      if (cmp == 0)
Packit ae235b
        {
Packit ae235b
          if (tree->value_destroy_func)
Packit ae235b
            tree->value_destroy_func (node->value);
Packit ae235b
Packit ae235b
          node->value = value;
Packit ae235b
Packit ae235b
          if (replace)
Packit ae235b
            {
Packit ae235b
              if (tree->key_destroy_func)
Packit ae235b
                tree->key_destroy_func (node->key);
Packit ae235b
Packit ae235b
              node->key = key;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              /* free the passed key */
Packit ae235b
              if (tree->key_destroy_func)
Packit ae235b
                tree->key_destroy_func (key);
Packit ae235b
            }
Packit ae235b
Packit ae235b
          return;
Packit ae235b
        }
Packit ae235b
      else if (cmp < 0)
Packit ae235b
        {
Packit ae235b
          if (node->left_child)
Packit ae235b
            {
Packit ae235b
              path[idx++] = node;
Packit ae235b
              node = node->left;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              GTreeNode *child = g_tree_node_new (key, value);
Packit ae235b
Packit ae235b
              child->left = node->left;
Packit ae235b
              child->right = node;
Packit ae235b
              node->left = child;
Packit ae235b
              node->left_child = TRUE;
Packit ae235b
              node->balance -= 1;
Packit ae235b
Packit ae235b
              tree->nnodes++;
Packit ae235b
Packit ae235b
              break;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          if (node->right_child)
Packit ae235b
            {
Packit ae235b
              path[idx++] = node;
Packit ae235b
              node = node->right;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              GTreeNode *child = g_tree_node_new (key, value);
Packit ae235b
Packit ae235b
              child->right = node->right;
Packit ae235b
              child->left = node;
Packit ae235b
              node->right = child;
Packit ae235b
              node->right_child = TRUE;
Packit ae235b
              node->balance += 1;
Packit ae235b
Packit ae235b
              tree->nnodes++;
Packit ae235b
Packit ae235b
              break;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Restore balance. This is the goodness of a non-recursive
Packit ae235b
   * implementation, when we are done with balancing we 'break'
Packit ae235b
   * the loop and we are done.
Packit ae235b
   */
Packit ae235b
  while (1)
Packit ae235b
    {
Packit ae235b
      GTreeNode *bparent = path[--idx];
Packit ae235b
      gboolean left_node = (bparent && node == bparent->left);
Packit ae235b
      g_assert (!bparent || bparent->left == node || bparent->right == node);
Packit ae235b
Packit ae235b
      if (node->balance < -1 || node->balance > 1)
Packit ae235b
        {
Packit ae235b
          node = g_tree_node_balance (node);
Packit ae235b
          if (bparent == NULL)
Packit ae235b
            tree->root = node;
Packit ae235b
          else if (left_node)
Packit ae235b
            bparent->left = node;
Packit ae235b
          else
Packit ae235b
            bparent->right = node;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      if (node->balance == 0 || bparent == NULL)
Packit ae235b
        break;
Packit ae235b
      
Packit ae235b
      if (left_node)
Packit ae235b
        bparent->balance -= 1;
Packit ae235b
      else
Packit ae235b
        bparent->balance += 1;
Packit ae235b
Packit ae235b
      node = bparent;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_remove:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @key: the key to remove
Packit ae235b
 * 
Packit ae235b
 * Removes a key/value pair from a #GTree.
Packit ae235b
 *
Packit ae235b
 * If the #GTree was created using g_tree_new_full(), the key and value 
Packit ae235b
 * are freed using the supplied destroy functions, otherwise you have to 
Packit ae235b
 * make sure that any dynamically allocated values are freed yourself.
Packit ae235b
 * If the key does not exist in the #GTree, the function does nothing.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if the key was found (prior to 2.8, this function
Packit ae235b
 *     returned nothing)
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_tree_remove (GTree         *tree,
Packit ae235b
               gconstpointer  key)
Packit ae235b
{
Packit ae235b
  gboolean removed;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (tree != NULL, FALSE);
Packit ae235b
Packit ae235b
  removed = g_tree_remove_internal (tree, key, FALSE);
Packit ae235b
Packit ae235b
#ifdef G_TREE_DEBUG
Packit ae235b
  g_tree_node_check (tree->root);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  return removed;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_steal:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @key: the key to remove
Packit ae235b
 * 
Packit ae235b
 * Removes a key and its associated value from a #GTree without calling 
Packit ae235b
 * the key and value destroy functions.
Packit ae235b
 *
Packit ae235b
 * If the key does not exist in the #GTree, the function does nothing.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if the key was found (prior to 2.8, this function
Packit ae235b
 *     returned nothing)
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_tree_steal (GTree         *tree,
Packit ae235b
              gconstpointer  key)
Packit ae235b
{
Packit ae235b
  gboolean removed;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (tree != NULL, FALSE);
Packit ae235b
Packit ae235b
  removed = g_tree_remove_internal (tree, key, TRUE);
Packit ae235b
Packit ae235b
#ifdef G_TREE_DEBUG
Packit ae235b
  g_tree_node_check (tree->root);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  return removed;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* internal remove routine */
Packit ae235b
static gboolean
Packit ae235b
g_tree_remove_internal (GTree         *tree,
Packit ae235b
                        gconstpointer  key,
Packit ae235b
                        gboolean       steal)
Packit ae235b
{
Packit ae235b
  GTreeNode *node, *parent, *balance;
Packit ae235b
  GTreeNode *path[MAX_GTREE_HEIGHT];
Packit ae235b
  int idx;
Packit ae235b
  gboolean left_node;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (tree != NULL, FALSE);
Packit ae235b
Packit ae235b
  if (!tree->root)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  idx = 0;
Packit ae235b
  path[idx++] = NULL;
Packit ae235b
  node = tree->root;
Packit ae235b
Packit ae235b
  while (1)
Packit ae235b
    {
Packit ae235b
      int cmp = tree->key_compare (key, node->key, tree->key_compare_data);
Packit ae235b
Packit ae235b
      if (cmp == 0)
Packit ae235b
        break;
Packit ae235b
      else if (cmp < 0)
Packit ae235b
        {
Packit ae235b
          if (!node->left_child)
Packit ae235b
            return FALSE;
Packit ae235b
Packit ae235b
          path[idx++] = node;
Packit ae235b
          node = node->left;
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          if (!node->right_child)
Packit ae235b
            return FALSE;
Packit ae235b
Packit ae235b
          path[idx++] = node;
Packit ae235b
          node = node->right;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* The following code is almost equal to g_tree_remove_node,
Packit ae235b
   * except that we do not have to call g_tree_node_parent.
Packit ae235b
   */
Packit ae235b
  balance = parent = path[--idx];
Packit ae235b
  g_assert (!parent || parent->left == node || parent->right == node);
Packit ae235b
  left_node = (parent && node == parent->left);
Packit ae235b
Packit ae235b
  if (!node->left_child)
Packit ae235b
    {
Packit ae235b
      if (!node->right_child)
Packit ae235b
        {
Packit ae235b
          if (!parent)
Packit ae235b
            tree->root = NULL;
Packit ae235b
          else if (left_node)
Packit ae235b
            {
Packit ae235b
              parent->left_child = FALSE;
Packit ae235b
              parent->left = node->left;
Packit ae235b
              parent->balance += 1;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              parent->right_child = FALSE;
Packit ae235b
              parent->right = node->right;
Packit ae235b
              parent->balance -= 1;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else /* node has a right child */
Packit ae235b
        {
Packit ae235b
          GTreeNode *tmp = g_tree_node_next (node);
Packit ae235b
          tmp->left = node->left;
Packit ae235b
Packit ae235b
          if (!parent)
Packit ae235b
            tree->root = node->right;
Packit ae235b
          else if (left_node)
Packit ae235b
            {
Packit ae235b
              parent->left = node->right;
Packit ae235b
              parent->balance += 1;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              parent->right = node->right;
Packit ae235b
              parent->balance -= 1;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  else /* node has a left child */
Packit ae235b
    {
Packit ae235b
      if (!node->right_child)
Packit ae235b
        {
Packit ae235b
          GTreeNode *tmp = g_tree_node_previous (node);
Packit ae235b
          tmp->right = node->right;
Packit ae235b
Packit ae235b
          if (parent == NULL)
Packit ae235b
            tree->root = node->left;
Packit ae235b
          else if (left_node)
Packit ae235b
            {
Packit ae235b
              parent->left = node->left;
Packit ae235b
              parent->balance += 1;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              parent->right = node->left;
Packit ae235b
              parent->balance -= 1;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else /* node has a both children (pant, pant!) */
Packit ae235b
        {
Packit ae235b
          GTreeNode *prev = node->left;
Packit ae235b
          GTreeNode *next = node->right;
Packit ae235b
          GTreeNode *nextp = node;
Packit ae235b
          int old_idx = idx + 1;
Packit ae235b
          idx++;
Packit ae235b
Packit ae235b
          /* path[idx] == parent */
Packit ae235b
          /* find the immediately next node (and its parent) */
Packit ae235b
          while (next->left_child)
Packit ae235b
            {
Packit ae235b
              path[++idx] = nextp = next;
Packit ae235b
              next = next->left;
Packit ae235b
            }
Packit ae235b
Packit ae235b
          path[old_idx] = next;
Packit ae235b
          balance = path[idx];
Packit ae235b
Packit ae235b
          /* remove 'next' from the tree */
Packit ae235b
          if (nextp != node)
Packit ae235b
            {
Packit ae235b
              if (next->right_child)
Packit ae235b
                nextp->left = next->right;
Packit ae235b
              else
Packit ae235b
                nextp->left_child = FALSE;
Packit ae235b
              nextp->balance += 1;
Packit ae235b
Packit ae235b
              next->right_child = TRUE;
Packit ae235b
              next->right = node->right;
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            node->balance -= 1;
Packit ae235b
Packit ae235b
          /* set the prev to point to the right place */
Packit ae235b
          while (prev->right_child)
Packit ae235b
            prev = prev->right;
Packit ae235b
          prev->right = next;
Packit ae235b
Packit ae235b
          /* prepare 'next' to replace 'node' */
Packit ae235b
          next->left_child = TRUE;
Packit ae235b
          next->left = node->left;
Packit ae235b
          next->balance = node->balance;
Packit ae235b
Packit ae235b
          if (!parent)
Packit ae235b
            tree->root = next;
Packit ae235b
          else if (left_node)
Packit ae235b
            parent->left = next;
Packit ae235b
          else
Packit ae235b
            parent->right = next;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* restore balance */
Packit ae235b
  if (balance)
Packit ae235b
    while (1)
Packit ae235b
      {
Packit ae235b
        GTreeNode *bparent = path[--idx];
Packit ae235b
        g_assert (!bparent || bparent->left == balance || bparent->right == balance);
Packit ae235b
        left_node = (bparent && balance == bparent->left);
Packit ae235b
Packit ae235b
        if(balance->balance < -1 || balance->balance > 1)
Packit ae235b
          {
Packit ae235b
            balance = g_tree_node_balance (balance);
Packit ae235b
            if (!bparent)
Packit ae235b
              tree->root = balance;
Packit ae235b
            else if (left_node)
Packit ae235b
              bparent->left = balance;
Packit ae235b
            else
Packit ae235b
              bparent->right = balance;
Packit ae235b
          }
Packit ae235b
Packit ae235b
        if (balance->balance != 0 || !bparent)
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        if (left_node)
Packit ae235b
          bparent->balance += 1;
Packit ae235b
        else
Packit ae235b
          bparent->balance -= 1;
Packit ae235b
Packit ae235b
        balance = bparent;
Packit ae235b
      }
Packit ae235b
Packit ae235b
  if (!steal)
Packit ae235b
    {
Packit ae235b
      if (tree->key_destroy_func)
Packit ae235b
        tree->key_destroy_func (node->key);
Packit ae235b
      if (tree->value_destroy_func)
Packit ae235b
        tree->value_destroy_func (node->value);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_slice_free (GTreeNode, node);
Packit ae235b
Packit ae235b
  tree->nnodes--;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_lookup:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @key: the key to look up
Packit ae235b
 * 
Packit ae235b
 * Gets the value corresponding to the given key. Since a #GTree is 
Packit ae235b
 * automatically balanced as key/value pairs are added, key lookup
Packit ae235b
 * is O(log n) (where n is the number of key/value pairs in the tree).
Packit ae235b
 *
Packit ae235b
 * Returns: the value corresponding to the key, or %NULL
Packit ae235b
 *     if the key was not found
Packit ae235b
 */
Packit ae235b
gpointer
Packit ae235b
g_tree_lookup (GTree         *tree,
Packit ae235b
               gconstpointer  key)
Packit ae235b
{
Packit ae235b
  GTreeNode *node;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (tree != NULL, NULL);
Packit ae235b
Packit ae235b
  node = g_tree_find_node (tree, key);
Packit ae235b
  
Packit ae235b
  return node ? node->value : NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_lookup_extended:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @lookup_key: the key to look up
Packit ae235b
 * @orig_key: (optional) (nullable): returns the original key
Packit ae235b
 * @value: (optional) (nullable): returns the value associated with the key
Packit ae235b
 * 
Packit ae235b
 * Looks up a key in the #GTree, returning the original key and the
Packit ae235b
 * associated value. This is useful if you need to free the memory
Packit ae235b
 * allocated for the original key, for example before calling
Packit ae235b
 * g_tree_remove().
Packit ae235b
 * 
Packit ae235b
 * Returns: %TRUE if the key was found in the #GTree
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_tree_lookup_extended (GTree         *tree,
Packit ae235b
                        gconstpointer  lookup_key,
Packit ae235b
                        gpointer      *orig_key,
Packit ae235b
                        gpointer      *value)
Packit ae235b
{
Packit ae235b
  GTreeNode *node;
Packit ae235b
  
Packit ae235b
  g_return_val_if_fail (tree != NULL, FALSE);
Packit ae235b
  
Packit ae235b
  node = g_tree_find_node (tree, lookup_key);
Packit ae235b
  
Packit ae235b
  if (node)
Packit ae235b
    {
Packit ae235b
      if (orig_key)
Packit ae235b
        *orig_key = node->key;
Packit ae235b
      if (value)
Packit ae235b
        *value = node->value;
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_foreach:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @func: the function to call for each node visited.
Packit ae235b
 *     If this function returns %TRUE, the traversal is stopped.
Packit ae235b
 * @user_data: user data to pass to the function
Packit ae235b
 *
Packit ae235b
 * Calls the given function for each of the key/value pairs in the #GTree.
Packit ae235b
 * The function is passed the key and value of each pair, and the given
Packit ae235b
 * @data parameter. The tree is traversed in sorted order.
Packit ae235b
 *
Packit ae235b
 * The tree may not be modified while iterating over it (you can't 
Packit ae235b
 * add/remove items). To remove all items matching a predicate, you need 
Packit ae235b
 * to add each item to a list in your #GTraverseFunc as you walk over 
Packit ae235b
 * the tree, then walk the list and remove each item.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_tree_foreach (GTree         *tree,
Packit ae235b
                GTraverseFunc  func,
Packit ae235b
                gpointer       user_data)
Packit ae235b
{
Packit ae235b
  GTreeNode *node;
Packit ae235b
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
  
Packit ae235b
  if (!tree->root)
Packit ae235b
    return;
Packit ae235b
Packit ae235b
  node = g_tree_first_node (tree);
Packit ae235b
  
Packit ae235b
  while (node)
Packit ae235b
    {
Packit ae235b
      if ((*func) (node->key, node->value, user_data))
Packit ae235b
        break;
Packit ae235b
      
Packit ae235b
      node = g_tree_node_next (node);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_traverse:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @traverse_func: the function to call for each node visited. If this 
Packit ae235b
 *   function returns %TRUE, the traversal is stopped.
Packit ae235b
 * @traverse_type: the order in which nodes are visited, one of %G_IN_ORDER,
Packit ae235b
 *   %G_PRE_ORDER and %G_POST_ORDER
Packit ae235b
 * @user_data: user data to pass to the function
Packit ae235b
 * 
Packit ae235b
 * Calls the given function for each node in the #GTree. 
Packit ae235b
 *
Packit ae235b
 * Deprecated:2.2: The order of a balanced tree is somewhat arbitrary.
Packit ae235b
 *     If you just want to visit all nodes in sorted order, use
Packit ae235b
 *     g_tree_foreach() instead. If you really need to visit nodes in
Packit ae235b
 *     a different order, consider using an [n-ary tree][glib-N-ary-Trees].
Packit ae235b
 */
Packit ae235b
/**
Packit ae235b
 * GTraverseFunc:
Packit ae235b
 * @key: a key of a #GTree node
Packit ae235b
 * @value: the value corresponding to the key
Packit ae235b
 * @data: user data passed to g_tree_traverse()
Packit ae235b
 *
Packit ae235b
 * Specifies the type of function passed to g_tree_traverse(). It is
Packit ae235b
 * passed the key and value of each node, together with the @user_data
Packit ae235b
 * parameter passed to g_tree_traverse(). If the function returns
Packit ae235b
 * %TRUE, the traversal is stopped.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE to stop the traversal
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_tree_traverse (GTree         *tree,
Packit ae235b
                 GTraverseFunc  traverse_func,
Packit ae235b
                 GTraverseType  traverse_type,
Packit ae235b
                 gpointer       user_data)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (tree != NULL);
Packit ae235b
Packit ae235b
  if (!tree->root)
Packit ae235b
    return;
Packit ae235b
Packit ae235b
  switch (traverse_type)
Packit ae235b
    {
Packit ae235b
    case G_PRE_ORDER:
Packit ae235b
      g_tree_node_pre_order (tree->root, traverse_func, user_data);
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_IN_ORDER:
Packit ae235b
      g_tree_node_in_order (tree->root, traverse_func, user_data);
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case G_POST_ORDER:
Packit ae235b
      g_tree_node_post_order (tree->root, traverse_func, user_data);
Packit ae235b
      break;
Packit ae235b
    
Packit ae235b
    case G_LEVEL_ORDER:
Packit ae235b
      g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
Packit ae235b
      break;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_search:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * @search_func: a function used to search the #GTree
Packit ae235b
 * @user_data: the data passed as the second argument to @search_func
Packit ae235b
 *
Packit ae235b
 * Searches a #GTree using @search_func.
Packit ae235b
 *
Packit ae235b
 * The @search_func is called with a pointer to the key of a key/value
Packit ae235b
 * pair in the tree, and the passed in @user_data. If @search_func returns
Packit ae235b
 * 0 for a key/value pair, then the corresponding value is returned as
Packit ae235b
 * the result of g_tree_search(). If @search_func returns -1, searching
Packit ae235b
 * will proceed among the key/value pairs that have a smaller key; if
Packit ae235b
 * @search_func returns 1, searching will proceed among the key/value
Packit ae235b
 * pairs that have a larger key.
Packit ae235b
 *
Packit ae235b
 * Returns: the value corresponding to the found key, or %NULL
Packit ae235b
 *     if the key was not found
Packit ae235b
 */
Packit ae235b
gpointer
Packit ae235b
g_tree_search (GTree         *tree,
Packit ae235b
               GCompareFunc   search_func,
Packit ae235b
               gconstpointer  user_data)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (tree != NULL, NULL);
Packit ae235b
Packit ae235b
  if (tree->root)
Packit ae235b
    return g_tree_node_search (tree->root, search_func, user_data);
Packit ae235b
  else
Packit ae235b
    return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_height:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * 
Packit ae235b
 * Gets the height of a #GTree.
Packit ae235b
 *
Packit ae235b
 * If the #GTree contains no nodes, the height is 0.
Packit ae235b
 * If the #GTree contains only one root node the height is 1.
Packit ae235b
 * If the root node has children the height is 2, etc.
Packit ae235b
 * 
Packit ae235b
 * Returns: the height of @tree
Packit ae235b
 */
Packit ae235b
gint
Packit ae235b
g_tree_height (GTree *tree)
Packit ae235b
{
Packit ae235b
  GTreeNode *node;
Packit ae235b
  gint height;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (tree != NULL, 0);
Packit ae235b
Packit ae235b
  if (!tree->root)
Packit ae235b
    return 0;
Packit ae235b
Packit ae235b
  height = 0;
Packit ae235b
  node = tree->root;
Packit ae235b
Packit ae235b
  while (1)
Packit ae235b
    {
Packit ae235b
      height += 1 + MAX(node->balance, 0);
Packit ae235b
Packit ae235b
      if (!node->left_child)
Packit ae235b
        return height;
Packit ae235b
      
Packit ae235b
      node = node->left;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_tree_nnodes:
Packit ae235b
 * @tree: a #GTree
Packit ae235b
 * 
Packit ae235b
 * Gets the number of nodes in a #GTree.
Packit ae235b
 * 
Packit ae235b
 * Returns: the number of nodes in @tree
Packit ae235b
 */
Packit ae235b
gint
Packit ae235b
g_tree_nnodes (GTree *tree)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (tree != NULL, 0);
Packit ae235b
Packit ae235b
  return tree->nnodes;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GTreeNode *
Packit ae235b
g_tree_node_balance (GTreeNode *node)
Packit ae235b
{
Packit ae235b
  if (node->balance < -1)
Packit ae235b
    {
Packit ae235b
      if (node->left->balance > 0)
Packit ae235b
        node->left = g_tree_node_rotate_left (node->left);
Packit ae235b
      node = g_tree_node_rotate_right (node);
Packit ae235b
    }
Packit ae235b
  else if (node->balance > 1)
Packit ae235b
    {
Packit ae235b
      if (node->right->balance < 0)
Packit ae235b
        node->right = g_tree_node_rotate_right (node->right);
Packit ae235b
      node = g_tree_node_rotate_left (node);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return node;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GTreeNode *
Packit ae235b
g_tree_find_node (GTree        *tree,
Packit ae235b
                  gconstpointer key)
Packit ae235b
{
Packit ae235b
  GTreeNode *node;
Packit ae235b
  gint cmp;
Packit ae235b
Packit ae235b
  node = tree->root;
Packit ae235b
  if (!node)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  while (1)
Packit ae235b
    {
Packit ae235b
      cmp = tree->key_compare (key, node->key, tree->key_compare_data);
Packit ae235b
      if (cmp == 0)
Packit ae235b
        return node;
Packit ae235b
      else if (cmp < 0)
Packit ae235b
        {
Packit ae235b
          if (!node->left_child)
Packit ae235b
            return NULL;
Packit ae235b
Packit ae235b
          node = node->left;
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          if (!node->right_child)
Packit ae235b
            return NULL;
Packit ae235b
Packit ae235b
          node = node->right;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static gint
Packit ae235b
g_tree_node_pre_order (GTreeNode     *node,
Packit ae235b
                       GTraverseFunc  traverse_func,
Packit ae235b
                       gpointer       data)
Packit ae235b
{
Packit ae235b
  if ((*traverse_func) (node->key, node->value, data))
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  if (node->left_child)
Packit ae235b
    {
Packit ae235b
      if (g_tree_node_pre_order (node->left, traverse_func, data))
Packit ae235b
        return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (node->right_child)
Packit ae235b
    {
Packit ae235b
      if (g_tree_node_pre_order (node->right, traverse_func, data))
Packit ae235b
        return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gint
Packit ae235b
g_tree_node_in_order (GTreeNode     *node,
Packit ae235b
                      GTraverseFunc  traverse_func,
Packit ae235b
                      gpointer       data)
Packit ae235b
{
Packit ae235b
  if (node->left_child)
Packit ae235b
    {
Packit ae235b
      if (g_tree_node_in_order (node->left, traverse_func, data))
Packit ae235b
        return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if ((*traverse_func) (node->key, node->value, data))
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  if (node->right_child)
Packit ae235b
    {
Packit ae235b
      if (g_tree_node_in_order (node->right, traverse_func, data))
Packit ae235b
        return TRUE;
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gint
Packit ae235b
g_tree_node_post_order (GTreeNode     *node,
Packit ae235b
                        GTraverseFunc  traverse_func,
Packit ae235b
                        gpointer       data)
Packit ae235b
{
Packit ae235b
  if (node->left_child)
Packit ae235b
    {
Packit ae235b
      if (g_tree_node_post_order (node->left, traverse_func, data))
Packit ae235b
        return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (node->right_child)
Packit ae235b
    {
Packit ae235b
      if (g_tree_node_post_order (node->right, traverse_func, data))
Packit ae235b
        return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if ((*traverse_func) (node->key, node->value, data))
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gpointer
Packit ae235b
g_tree_node_search (GTreeNode     *node,
Packit ae235b
                    GCompareFunc   search_func,
Packit ae235b
                    gconstpointer  data)
Packit ae235b
{
Packit ae235b
  gint dir;
Packit ae235b
Packit ae235b
  if (!node)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  while (1) 
Packit ae235b
    {
Packit ae235b
      dir = (* search_func) (node->key, data);
Packit ae235b
      if (dir == 0)
Packit ae235b
        return node->value;
Packit ae235b
      else if (dir < 0) 
Packit ae235b
        {
Packit ae235b
          if (!node->left_child)
Packit ae235b
            return NULL;
Packit ae235b
Packit ae235b
          node = node->left;
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          if (!node->right_child)
Packit ae235b
            return NULL;
Packit ae235b
Packit ae235b
          node = node->right;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static GTreeNode *
Packit ae235b
g_tree_node_rotate_left (GTreeNode *node)
Packit ae235b
{
Packit ae235b
  GTreeNode *right;
Packit ae235b
  gint a_bal;
Packit ae235b
  gint b_bal;
Packit ae235b
Packit ae235b
  right = node->right;
Packit ae235b
Packit ae235b
  if (right->left_child)
Packit ae235b
    node->right = right->left;
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      node->right_child = FALSE;
Packit ae235b
      right->left_child = TRUE;
Packit ae235b
    }
Packit ae235b
  right->left = node;
Packit ae235b
Packit ae235b
  a_bal = node->balance;
Packit ae235b
  b_bal = right->balance;
Packit ae235b
Packit ae235b
  if (b_bal <= 0)
Packit ae235b
    {
Packit ae235b
      if (a_bal >= 1)
Packit ae235b
        right->balance = b_bal - 1;
Packit ae235b
      else
Packit ae235b
        right->balance = a_bal + b_bal - 2;
Packit ae235b
      node->balance = a_bal - 1;
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      if (a_bal <= b_bal)
Packit ae235b
        right->balance = a_bal - 2;
Packit ae235b
      else
Packit ae235b
        right->balance = b_bal - 1;
Packit ae235b
      node->balance = a_bal - b_bal - 1;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return right;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GTreeNode *
Packit ae235b
g_tree_node_rotate_right (GTreeNode *node)
Packit ae235b
{
Packit ae235b
  GTreeNode *left;
Packit ae235b
  gint a_bal;
Packit ae235b
  gint b_bal;
Packit ae235b
Packit ae235b
  left = node->left;
Packit ae235b
Packit ae235b
  if (left->right_child)
Packit ae235b
    node->left = left->right;
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      node->left_child = FALSE;
Packit ae235b
      left->right_child = TRUE;
Packit ae235b
    }
Packit ae235b
  left->right = node;
Packit ae235b
Packit ae235b
  a_bal = node->balance;
Packit ae235b
  b_bal = left->balance;
Packit ae235b
Packit ae235b
  if (b_bal <= 0)
Packit ae235b
    {
Packit ae235b
      if (b_bal > a_bal)
Packit ae235b
        left->balance = b_bal + 1;
Packit ae235b
      else
Packit ae235b
        left->balance = a_bal + 2;
Packit ae235b
      node->balance = a_bal - b_bal + 1;
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      if (a_bal <= -1)
Packit ae235b
        left->balance = b_bal + 1;
Packit ae235b
      else
Packit ae235b
        left->balance = a_bal + b_bal + 2;
Packit ae235b
      node->balance = a_bal + 1;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return left;
Packit ae235b
}
Packit ae235b
Packit ae235b
#ifdef G_TREE_DEBUG
Packit ae235b
static gint
Packit ae235b
g_tree_node_height (GTreeNode *node)
Packit ae235b
{
Packit ae235b
  gint left_height;
Packit ae235b
  gint right_height;
Packit ae235b
Packit ae235b
  if (node)
Packit ae235b
    {
Packit ae235b
      left_height = 0;
Packit ae235b
      right_height = 0;
Packit ae235b
Packit ae235b
      if (node->left_child)
Packit ae235b
        left_height = g_tree_node_height (node->left);
Packit ae235b
Packit ae235b
      if (node->right_child)
Packit ae235b
        right_height = g_tree_node_height (node->right);
Packit ae235b
Packit ae235b
      return MAX (left_height, right_height) + 1;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_tree_node_check (GTreeNode *node)
Packit ae235b
{
Packit ae235b
  gint left_height;
Packit ae235b
  gint right_height;
Packit ae235b
  gint balance;
Packit ae235b
  GTreeNode *tmp;
Packit ae235b
Packit ae235b
  if (node)
Packit ae235b
    {
Packit ae235b
      if (node->left_child)
Packit ae235b
        {
Packit ae235b
          tmp = g_tree_node_previous (node);
Packit ae235b
          g_assert (tmp->right == node);
Packit ae235b
        }
Packit ae235b
Packit ae235b
      if (node->right_child)
Packit ae235b
        {
Packit ae235b
          tmp = g_tree_node_next (node);
Packit ae235b
          g_assert (tmp->left == node);
Packit ae235b
        }
Packit ae235b
Packit ae235b
      left_height = 0;
Packit ae235b
      right_height = 0;
Packit ae235b
      
Packit ae235b
      if (node->left_child)
Packit ae235b
        left_height = g_tree_node_height (node->left);
Packit ae235b
      if (node->right_child)
Packit ae235b
        right_height = g_tree_node_height (node->right);
Packit ae235b
      
Packit ae235b
      balance = right_height - left_height;
Packit ae235b
      g_assert (balance == node->balance);
Packit ae235b
      
Packit ae235b
      if (node->left_child)
Packit ae235b
        g_tree_node_check (node->left);
Packit ae235b
      if (node->right_child)
Packit ae235b
        g_tree_node_check (node->right);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_tree_node_dump (GTreeNode *node, 
Packit ae235b
                  gint       indent)
Packit ae235b
{
Packit ae235b
  g_print ("%*s%c\n", indent, "", *(char *)node->key);
Packit ae235b
Packit ae235b
  if (node->left_child)
Packit ae235b
    g_tree_node_dump (node->left, indent + 2);
Packit ae235b
  else if (node->left)
Packit ae235b
    g_print ("%*s<%c\n", indent + 2, "", *(char *)node->left->key);
Packit ae235b
Packit ae235b
  if (node->right_child)
Packit ae235b
    g_tree_node_dump (node->right, indent + 2);
Packit ae235b
  else if (node->right)
Packit ae235b
    g_print ("%*s>%c\n", indent + 2, "", *(char *)node->right->key);
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
void
Packit ae235b
g_tree_dump (GTree *tree)
Packit ae235b
{
Packit ae235b
  if (tree->root)
Packit ae235b
    g_tree_node_dump (tree->root, 0);
Packit ae235b
}
Packit ae235b
#endif