1*e3feb2ccSEmilio Cota /* 2*e3feb2ccSEmilio Cota * GLIB - Library of useful routines for C programming 3*e3feb2ccSEmilio Cota * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald 4*e3feb2ccSEmilio Cota * 5*e3feb2ccSEmilio Cota * SPDX-License-Identifier: LGPL-2.1-or-later 6*e3feb2ccSEmilio Cota * 7*e3feb2ccSEmilio Cota * This library is free software; you can redistribute it and/or 8*e3feb2ccSEmilio Cota * modify it under the terms of the GNU Lesser General Public 9*e3feb2ccSEmilio Cota * License as published by the Free Software Foundation; either 10*e3feb2ccSEmilio Cota * version 2.1 of the License, or (at your option) any later version. 11*e3feb2ccSEmilio Cota * 12*e3feb2ccSEmilio Cota * This library is distributed in the hope that it will be useful, 13*e3feb2ccSEmilio Cota * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*e3feb2ccSEmilio Cota * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15*e3feb2ccSEmilio Cota * Lesser General Public License for more details. 16*e3feb2ccSEmilio Cota * 17*e3feb2ccSEmilio Cota * You should have received a copy of the GNU Lesser General Public 18*e3feb2ccSEmilio Cota * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19*e3feb2ccSEmilio Cota */ 20*e3feb2ccSEmilio Cota 21*e3feb2ccSEmilio Cota /* 22*e3feb2ccSEmilio Cota * Modified by the GLib Team and others 1997-2000. See the AUTHORS 23*e3feb2ccSEmilio Cota * file for a list of people on the GLib Team. See the ChangeLog 24*e3feb2ccSEmilio Cota * files for a list of changes. These files are distributed with 25*e3feb2ccSEmilio Cota * GLib at ftp://ftp.gtk.org/pub/gtk/. 26*e3feb2ccSEmilio Cota */ 27*e3feb2ccSEmilio Cota 28*e3feb2ccSEmilio Cota /* 29*e3feb2ccSEmilio Cota * MT safe 30*e3feb2ccSEmilio Cota */ 31*e3feb2ccSEmilio Cota 32*e3feb2ccSEmilio Cota #include "qemu/osdep.h" 33*e3feb2ccSEmilio Cota #include "qemu/qtree.h" 34*e3feb2ccSEmilio Cota 35*e3feb2ccSEmilio Cota /** 36*e3feb2ccSEmilio Cota * SECTION:trees-binary 37*e3feb2ccSEmilio Cota * @title: Balanced Binary Trees 38*e3feb2ccSEmilio Cota * @short_description: a sorted collection of key/value pairs optimized 39*e3feb2ccSEmilio Cota * for searching and traversing in order 40*e3feb2ccSEmilio Cota * 41*e3feb2ccSEmilio Cota * The #QTree structure and its associated functions provide a sorted 42*e3feb2ccSEmilio Cota * collection of key/value pairs optimized for searching and traversing 43*e3feb2ccSEmilio Cota * in order. This means that most of the operations (access, search, 44*e3feb2ccSEmilio Cota * insertion, deletion, ...) on #QTree are O(log(n)) in average and O(n) 45*e3feb2ccSEmilio Cota * in worst case for time complexity. But, note that maintaining a 46*e3feb2ccSEmilio Cota * balanced sorted #QTree of n elements is done in time O(n log(n)). 47*e3feb2ccSEmilio Cota * 48*e3feb2ccSEmilio Cota * To create a new #QTree use q_tree_new(). 49*e3feb2ccSEmilio Cota * 50*e3feb2ccSEmilio Cota * To insert a key/value pair into a #QTree use q_tree_insert() 51*e3feb2ccSEmilio Cota * (O(n log(n))). 52*e3feb2ccSEmilio Cota * 53*e3feb2ccSEmilio Cota * To remove a key/value pair use q_tree_remove() (O(n log(n))). 54*e3feb2ccSEmilio Cota * 55*e3feb2ccSEmilio Cota * To look up the value corresponding to a given key, use 56*e3feb2ccSEmilio Cota * q_tree_lookup() and q_tree_lookup_extended(). 57*e3feb2ccSEmilio Cota * 58*e3feb2ccSEmilio Cota * To find out the number of nodes in a #QTree, use q_tree_nnodes(). To 59*e3feb2ccSEmilio Cota * get the height of a #QTree, use q_tree_height(). 60*e3feb2ccSEmilio Cota * 61*e3feb2ccSEmilio Cota * To traverse a #QTree, calling a function for each node visited in 62*e3feb2ccSEmilio Cota * the traversal, use q_tree_foreach(). 63*e3feb2ccSEmilio Cota * 64*e3feb2ccSEmilio Cota * To destroy a #QTree, use q_tree_destroy(). 65*e3feb2ccSEmilio Cota **/ 66*e3feb2ccSEmilio Cota 67*e3feb2ccSEmilio Cota #define MAX_GTREE_HEIGHT 40 68*e3feb2ccSEmilio Cota 69*e3feb2ccSEmilio Cota /** 70*e3feb2ccSEmilio Cota * QTree: 71*e3feb2ccSEmilio Cota * 72*e3feb2ccSEmilio Cota * The QTree struct is an opaque data structure representing a 73*e3feb2ccSEmilio Cota * [balanced binary tree][glib-Balanced-Binary-Trees]. It should be 74*e3feb2ccSEmilio Cota * accessed only by using the following functions. 75*e3feb2ccSEmilio Cota */ 76*e3feb2ccSEmilio Cota struct _QTree { 77*e3feb2ccSEmilio Cota QTreeNode *root; 78*e3feb2ccSEmilio Cota GCompareDataFunc key_compare; 79*e3feb2ccSEmilio Cota GDestroyNotify key_destroy_func; 80*e3feb2ccSEmilio Cota GDestroyNotify value_destroy_func; 81*e3feb2ccSEmilio Cota gpointer key_compare_data; 82*e3feb2ccSEmilio Cota guint nnodes; 83*e3feb2ccSEmilio Cota gint ref_count; 84*e3feb2ccSEmilio Cota }; 85*e3feb2ccSEmilio Cota 86*e3feb2ccSEmilio Cota struct _QTreeNode { 87*e3feb2ccSEmilio Cota gpointer key; /* key for this node */ 88*e3feb2ccSEmilio Cota gpointer value; /* value stored at this node */ 89*e3feb2ccSEmilio Cota QTreeNode *left; /* left subtree */ 90*e3feb2ccSEmilio Cota QTreeNode *right; /* right subtree */ 91*e3feb2ccSEmilio Cota gint8 balance; /* height (right) - height (left) */ 92*e3feb2ccSEmilio Cota guint8 left_child; 93*e3feb2ccSEmilio Cota guint8 right_child; 94*e3feb2ccSEmilio Cota }; 95*e3feb2ccSEmilio Cota 96*e3feb2ccSEmilio Cota 97*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_new(gpointer key, 98*e3feb2ccSEmilio Cota gpointer value); 99*e3feb2ccSEmilio Cota static QTreeNode *q_tree_insert_internal(QTree *tree, 100*e3feb2ccSEmilio Cota gpointer key, 101*e3feb2ccSEmilio Cota gpointer value, 102*e3feb2ccSEmilio Cota gboolean replace); 103*e3feb2ccSEmilio Cota static gboolean q_tree_remove_internal(QTree *tree, 104*e3feb2ccSEmilio Cota gconstpointer key, 105*e3feb2ccSEmilio Cota gboolean steal); 106*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_balance(QTreeNode *node); 107*e3feb2ccSEmilio Cota static QTreeNode *q_tree_find_node(QTree *tree, 108*e3feb2ccSEmilio Cota gconstpointer key); 109*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_search(QTreeNode *node, 110*e3feb2ccSEmilio Cota GCompareFunc search_func, 111*e3feb2ccSEmilio Cota gconstpointer data); 112*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_rotate_left(QTreeNode *node); 113*e3feb2ccSEmilio Cota static QTreeNode *q_tree_node_rotate_right(QTreeNode *node); 114*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 115*e3feb2ccSEmilio Cota static void q_tree_node_check(QTreeNode *node); 116*e3feb2ccSEmilio Cota #endif 117*e3feb2ccSEmilio Cota 118*e3feb2ccSEmilio Cota static QTreeNode* 119*e3feb2ccSEmilio Cota q_tree_node_new(gpointer key, 120*e3feb2ccSEmilio Cota gpointer value) 121*e3feb2ccSEmilio Cota { 122*e3feb2ccSEmilio Cota QTreeNode *node = g_new(QTreeNode, 1); 123*e3feb2ccSEmilio Cota 124*e3feb2ccSEmilio Cota node->balance = 0; 125*e3feb2ccSEmilio Cota node->left = NULL; 126*e3feb2ccSEmilio Cota node->right = NULL; 127*e3feb2ccSEmilio Cota node->left_child = FALSE; 128*e3feb2ccSEmilio Cota node->right_child = FALSE; 129*e3feb2ccSEmilio Cota node->key = key; 130*e3feb2ccSEmilio Cota node->value = value; 131*e3feb2ccSEmilio Cota 132*e3feb2ccSEmilio Cota return node; 133*e3feb2ccSEmilio Cota } 134*e3feb2ccSEmilio Cota 135*e3feb2ccSEmilio Cota /** 136*e3feb2ccSEmilio Cota * q_tree_new: 137*e3feb2ccSEmilio Cota * @key_compare_func: the function used to order the nodes in the #QTree. 138*e3feb2ccSEmilio Cota * It should return values similar to the standard strcmp() function - 139*e3feb2ccSEmilio Cota * 0 if the two arguments are equal, a negative value if the first argument 140*e3feb2ccSEmilio Cota * comes before the second, or a positive value if the first argument comes 141*e3feb2ccSEmilio Cota * after the second. 142*e3feb2ccSEmilio Cota * 143*e3feb2ccSEmilio Cota * Creates a new #QTree. 144*e3feb2ccSEmilio Cota * 145*e3feb2ccSEmilio Cota * Returns: a newly allocated #QTree 146*e3feb2ccSEmilio Cota */ 147*e3feb2ccSEmilio Cota QTree * 148*e3feb2ccSEmilio Cota q_tree_new(GCompareFunc key_compare_func) 149*e3feb2ccSEmilio Cota { 150*e3feb2ccSEmilio Cota g_return_val_if_fail(key_compare_func != NULL, NULL); 151*e3feb2ccSEmilio Cota 152*e3feb2ccSEmilio Cota return q_tree_new_full((GCompareDataFunc) key_compare_func, NULL, 153*e3feb2ccSEmilio Cota NULL, NULL); 154*e3feb2ccSEmilio Cota } 155*e3feb2ccSEmilio Cota 156*e3feb2ccSEmilio Cota /** 157*e3feb2ccSEmilio Cota * q_tree_new_with_data: 158*e3feb2ccSEmilio Cota * @key_compare_func: qsort()-style comparison function 159*e3feb2ccSEmilio Cota * @key_compare_data: data to pass to comparison function 160*e3feb2ccSEmilio Cota * 161*e3feb2ccSEmilio Cota * Creates a new #QTree with a comparison function that accepts user data. 162*e3feb2ccSEmilio Cota * See q_tree_new() for more details. 163*e3feb2ccSEmilio Cota * 164*e3feb2ccSEmilio Cota * Returns: a newly allocated #QTree 165*e3feb2ccSEmilio Cota */ 166*e3feb2ccSEmilio Cota QTree * 167*e3feb2ccSEmilio Cota q_tree_new_with_data(GCompareDataFunc key_compare_func, 168*e3feb2ccSEmilio Cota gpointer key_compare_data) 169*e3feb2ccSEmilio Cota { 170*e3feb2ccSEmilio Cota g_return_val_if_fail(key_compare_func != NULL, NULL); 171*e3feb2ccSEmilio Cota 172*e3feb2ccSEmilio Cota return q_tree_new_full(key_compare_func, key_compare_data, 173*e3feb2ccSEmilio Cota NULL, NULL); 174*e3feb2ccSEmilio Cota } 175*e3feb2ccSEmilio Cota 176*e3feb2ccSEmilio Cota /** 177*e3feb2ccSEmilio Cota * q_tree_new_full: 178*e3feb2ccSEmilio Cota * @key_compare_func: qsort()-style comparison function 179*e3feb2ccSEmilio Cota * @key_compare_data: data to pass to comparison function 180*e3feb2ccSEmilio Cota * @key_destroy_func: a function to free the memory allocated for the key 181*e3feb2ccSEmilio Cota * used when removing the entry from the #QTree or %NULL if you don't 182*e3feb2ccSEmilio Cota * want to supply such a function 183*e3feb2ccSEmilio Cota * @value_destroy_func: a function to free the memory allocated for the 184*e3feb2ccSEmilio Cota * value used when removing the entry from the #QTree or %NULL if you 185*e3feb2ccSEmilio Cota * don't want to supply such a function 186*e3feb2ccSEmilio Cota * 187*e3feb2ccSEmilio Cota * Creates a new #QTree like q_tree_new() and allows to specify functions 188*e3feb2ccSEmilio Cota * to free the memory allocated for the key and value that get called when 189*e3feb2ccSEmilio Cota * removing the entry from the #QTree. 190*e3feb2ccSEmilio Cota * 191*e3feb2ccSEmilio Cota * Returns: a newly allocated #QTree 192*e3feb2ccSEmilio Cota */ 193*e3feb2ccSEmilio Cota QTree * 194*e3feb2ccSEmilio Cota q_tree_new_full(GCompareDataFunc key_compare_func, 195*e3feb2ccSEmilio Cota gpointer key_compare_data, 196*e3feb2ccSEmilio Cota GDestroyNotify key_destroy_func, 197*e3feb2ccSEmilio Cota GDestroyNotify value_destroy_func) 198*e3feb2ccSEmilio Cota { 199*e3feb2ccSEmilio Cota QTree *tree; 200*e3feb2ccSEmilio Cota 201*e3feb2ccSEmilio Cota g_return_val_if_fail(key_compare_func != NULL, NULL); 202*e3feb2ccSEmilio Cota 203*e3feb2ccSEmilio Cota tree = g_new(QTree, 1); 204*e3feb2ccSEmilio Cota tree->root = NULL; 205*e3feb2ccSEmilio Cota tree->key_compare = key_compare_func; 206*e3feb2ccSEmilio Cota tree->key_destroy_func = key_destroy_func; 207*e3feb2ccSEmilio Cota tree->value_destroy_func = value_destroy_func; 208*e3feb2ccSEmilio Cota tree->key_compare_data = key_compare_data; 209*e3feb2ccSEmilio Cota tree->nnodes = 0; 210*e3feb2ccSEmilio Cota tree->ref_count = 1; 211*e3feb2ccSEmilio Cota 212*e3feb2ccSEmilio Cota return tree; 213*e3feb2ccSEmilio Cota } 214*e3feb2ccSEmilio Cota 215*e3feb2ccSEmilio Cota /** 216*e3feb2ccSEmilio Cota * q_tree_node_first: 217*e3feb2ccSEmilio Cota * @tree: a #QTree 218*e3feb2ccSEmilio Cota * 219*e3feb2ccSEmilio Cota * Returns the first in-order node of the tree, or %NULL 220*e3feb2ccSEmilio Cota * for an empty tree. 221*e3feb2ccSEmilio Cota * 222*e3feb2ccSEmilio Cota * Returns: (nullable) (transfer none): the first node in the tree 223*e3feb2ccSEmilio Cota * 224*e3feb2ccSEmilio Cota * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API. 225*e3feb2ccSEmilio Cota */ 226*e3feb2ccSEmilio Cota static QTreeNode * 227*e3feb2ccSEmilio Cota q_tree_node_first(QTree *tree) 228*e3feb2ccSEmilio Cota { 229*e3feb2ccSEmilio Cota QTreeNode *tmp; 230*e3feb2ccSEmilio Cota 231*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, NULL); 232*e3feb2ccSEmilio Cota 233*e3feb2ccSEmilio Cota if (!tree->root) { 234*e3feb2ccSEmilio Cota return NULL; 235*e3feb2ccSEmilio Cota } 236*e3feb2ccSEmilio Cota 237*e3feb2ccSEmilio Cota tmp = tree->root; 238*e3feb2ccSEmilio Cota 239*e3feb2ccSEmilio Cota while (tmp->left_child) { 240*e3feb2ccSEmilio Cota tmp = tmp->left; 241*e3feb2ccSEmilio Cota } 242*e3feb2ccSEmilio Cota 243*e3feb2ccSEmilio Cota return tmp; 244*e3feb2ccSEmilio Cota } 245*e3feb2ccSEmilio Cota 246*e3feb2ccSEmilio Cota /** 247*e3feb2ccSEmilio Cota * q_tree_node_previous 248*e3feb2ccSEmilio Cota * @node: a #QTree node 249*e3feb2ccSEmilio Cota * 250*e3feb2ccSEmilio Cota * Returns the previous in-order node of the tree, or %NULL 251*e3feb2ccSEmilio Cota * if the passed node was already the first one. 252*e3feb2ccSEmilio Cota * 253*e3feb2ccSEmilio Cota * Returns: (nullable) (transfer none): the previous node in the tree 254*e3feb2ccSEmilio Cota * 255*e3feb2ccSEmilio Cota * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API. 256*e3feb2ccSEmilio Cota */ 257*e3feb2ccSEmilio Cota static QTreeNode * 258*e3feb2ccSEmilio Cota q_tree_node_previous(QTreeNode *node) 259*e3feb2ccSEmilio Cota { 260*e3feb2ccSEmilio Cota QTreeNode *tmp; 261*e3feb2ccSEmilio Cota 262*e3feb2ccSEmilio Cota g_return_val_if_fail(node != NULL, NULL); 263*e3feb2ccSEmilio Cota 264*e3feb2ccSEmilio Cota tmp = node->left; 265*e3feb2ccSEmilio Cota 266*e3feb2ccSEmilio Cota if (node->left_child) { 267*e3feb2ccSEmilio Cota while (tmp->right_child) { 268*e3feb2ccSEmilio Cota tmp = tmp->right; 269*e3feb2ccSEmilio Cota } 270*e3feb2ccSEmilio Cota } 271*e3feb2ccSEmilio Cota 272*e3feb2ccSEmilio Cota return tmp; 273*e3feb2ccSEmilio Cota } 274*e3feb2ccSEmilio Cota 275*e3feb2ccSEmilio Cota /** 276*e3feb2ccSEmilio Cota * q_tree_node_next 277*e3feb2ccSEmilio Cota * @node: a #QTree node 278*e3feb2ccSEmilio Cota * 279*e3feb2ccSEmilio Cota * Returns the next in-order node of the tree, or %NULL 280*e3feb2ccSEmilio Cota * if the passed node was already the last one. 281*e3feb2ccSEmilio Cota * 282*e3feb2ccSEmilio Cota * Returns: (nullable) (transfer none): the next node in the tree 283*e3feb2ccSEmilio Cota * 284*e3feb2ccSEmilio Cota * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API. 285*e3feb2ccSEmilio Cota */ 286*e3feb2ccSEmilio Cota static QTreeNode * 287*e3feb2ccSEmilio Cota q_tree_node_next(QTreeNode *node) 288*e3feb2ccSEmilio Cota { 289*e3feb2ccSEmilio Cota QTreeNode *tmp; 290*e3feb2ccSEmilio Cota 291*e3feb2ccSEmilio Cota g_return_val_if_fail(node != NULL, NULL); 292*e3feb2ccSEmilio Cota 293*e3feb2ccSEmilio Cota tmp = node->right; 294*e3feb2ccSEmilio Cota 295*e3feb2ccSEmilio Cota if (node->right_child) { 296*e3feb2ccSEmilio Cota while (tmp->left_child) { 297*e3feb2ccSEmilio Cota tmp = tmp->left; 298*e3feb2ccSEmilio Cota } 299*e3feb2ccSEmilio Cota } 300*e3feb2ccSEmilio Cota 301*e3feb2ccSEmilio Cota return tmp; 302*e3feb2ccSEmilio Cota } 303*e3feb2ccSEmilio Cota 304*e3feb2ccSEmilio Cota /** 305*e3feb2ccSEmilio Cota * q_tree_remove_all: 306*e3feb2ccSEmilio Cota * @tree: a #QTree 307*e3feb2ccSEmilio Cota * 308*e3feb2ccSEmilio Cota * Removes all nodes from a #QTree and destroys their keys and values, 309*e3feb2ccSEmilio Cota * then resets the #QTree’s root to %NULL. 310*e3feb2ccSEmilio Cota * 311*e3feb2ccSEmilio Cota * Since: 2.70 in GLib. Internal in Qtree, i.e. not in the public API. 312*e3feb2ccSEmilio Cota */ 313*e3feb2ccSEmilio Cota static void 314*e3feb2ccSEmilio Cota q_tree_remove_all(QTree *tree) 315*e3feb2ccSEmilio Cota { 316*e3feb2ccSEmilio Cota QTreeNode *node; 317*e3feb2ccSEmilio Cota QTreeNode *next; 318*e3feb2ccSEmilio Cota 319*e3feb2ccSEmilio Cota g_return_if_fail(tree != NULL); 320*e3feb2ccSEmilio Cota 321*e3feb2ccSEmilio Cota node = q_tree_node_first(tree); 322*e3feb2ccSEmilio Cota 323*e3feb2ccSEmilio Cota while (node) { 324*e3feb2ccSEmilio Cota next = q_tree_node_next(node); 325*e3feb2ccSEmilio Cota 326*e3feb2ccSEmilio Cota if (tree->key_destroy_func) { 327*e3feb2ccSEmilio Cota tree->key_destroy_func(node->key); 328*e3feb2ccSEmilio Cota } 329*e3feb2ccSEmilio Cota if (tree->value_destroy_func) { 330*e3feb2ccSEmilio Cota tree->value_destroy_func(node->value); 331*e3feb2ccSEmilio Cota } 332*e3feb2ccSEmilio Cota g_free(node); 333*e3feb2ccSEmilio Cota 334*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 335*e3feb2ccSEmilio Cota g_assert(tree->nnodes > 0); 336*e3feb2ccSEmilio Cota tree->nnodes--; 337*e3feb2ccSEmilio Cota #endif 338*e3feb2ccSEmilio Cota 339*e3feb2ccSEmilio Cota node = next; 340*e3feb2ccSEmilio Cota } 341*e3feb2ccSEmilio Cota 342*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 343*e3feb2ccSEmilio Cota g_assert(tree->nnodes == 0); 344*e3feb2ccSEmilio Cota #endif 345*e3feb2ccSEmilio Cota 346*e3feb2ccSEmilio Cota tree->root = NULL; 347*e3feb2ccSEmilio Cota #ifndef Q_TREE_DEBUG 348*e3feb2ccSEmilio Cota tree->nnodes = 0; 349*e3feb2ccSEmilio Cota #endif 350*e3feb2ccSEmilio Cota } 351*e3feb2ccSEmilio Cota 352*e3feb2ccSEmilio Cota /** 353*e3feb2ccSEmilio Cota * q_tree_ref: 354*e3feb2ccSEmilio Cota * @tree: a #QTree 355*e3feb2ccSEmilio Cota * 356*e3feb2ccSEmilio Cota * Increments the reference count of @tree by one. 357*e3feb2ccSEmilio Cota * 358*e3feb2ccSEmilio Cota * It is safe to call this function from any thread. 359*e3feb2ccSEmilio Cota * 360*e3feb2ccSEmilio Cota * Returns: the passed in #QTree 361*e3feb2ccSEmilio Cota * 362*e3feb2ccSEmilio Cota * Since: 2.22 363*e3feb2ccSEmilio Cota */ 364*e3feb2ccSEmilio Cota QTree * 365*e3feb2ccSEmilio Cota q_tree_ref(QTree *tree) 366*e3feb2ccSEmilio Cota { 367*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, NULL); 368*e3feb2ccSEmilio Cota 369*e3feb2ccSEmilio Cota g_atomic_int_inc(&tree->ref_count); 370*e3feb2ccSEmilio Cota 371*e3feb2ccSEmilio Cota return tree; 372*e3feb2ccSEmilio Cota } 373*e3feb2ccSEmilio Cota 374*e3feb2ccSEmilio Cota /** 375*e3feb2ccSEmilio Cota * q_tree_unref: 376*e3feb2ccSEmilio Cota * @tree: a #QTree 377*e3feb2ccSEmilio Cota * 378*e3feb2ccSEmilio Cota * Decrements the reference count of @tree by one. 379*e3feb2ccSEmilio Cota * If the reference count drops to 0, all keys and values will 380*e3feb2ccSEmilio Cota * be destroyed (if destroy functions were specified) and all 381*e3feb2ccSEmilio Cota * memory allocated by @tree will be released. 382*e3feb2ccSEmilio Cota * 383*e3feb2ccSEmilio Cota * It is safe to call this function from any thread. 384*e3feb2ccSEmilio Cota * 385*e3feb2ccSEmilio Cota * Since: 2.22 386*e3feb2ccSEmilio Cota */ 387*e3feb2ccSEmilio Cota void 388*e3feb2ccSEmilio Cota q_tree_unref(QTree *tree) 389*e3feb2ccSEmilio Cota { 390*e3feb2ccSEmilio Cota g_return_if_fail(tree != NULL); 391*e3feb2ccSEmilio Cota 392*e3feb2ccSEmilio Cota if (g_atomic_int_dec_and_test(&tree->ref_count)) { 393*e3feb2ccSEmilio Cota q_tree_remove_all(tree); 394*e3feb2ccSEmilio Cota g_free(tree); 395*e3feb2ccSEmilio Cota } 396*e3feb2ccSEmilio Cota } 397*e3feb2ccSEmilio Cota 398*e3feb2ccSEmilio Cota /** 399*e3feb2ccSEmilio Cota * q_tree_destroy: 400*e3feb2ccSEmilio Cota * @tree: a #QTree 401*e3feb2ccSEmilio Cota * 402*e3feb2ccSEmilio Cota * Removes all keys and values from the #QTree and decreases its 403*e3feb2ccSEmilio Cota * reference count by one. If keys and/or values are dynamically 404*e3feb2ccSEmilio Cota * allocated, you should either free them first or create the #QTree 405*e3feb2ccSEmilio Cota * using q_tree_new_full(). In the latter case the destroy functions 406*e3feb2ccSEmilio Cota * you supplied will be called on all keys and values before destroying 407*e3feb2ccSEmilio Cota * the #QTree. 408*e3feb2ccSEmilio Cota */ 409*e3feb2ccSEmilio Cota void 410*e3feb2ccSEmilio Cota q_tree_destroy(QTree *tree) 411*e3feb2ccSEmilio Cota { 412*e3feb2ccSEmilio Cota g_return_if_fail(tree != NULL); 413*e3feb2ccSEmilio Cota 414*e3feb2ccSEmilio Cota q_tree_remove_all(tree); 415*e3feb2ccSEmilio Cota q_tree_unref(tree); 416*e3feb2ccSEmilio Cota } 417*e3feb2ccSEmilio Cota 418*e3feb2ccSEmilio Cota /** 419*e3feb2ccSEmilio Cota * q_tree_insert_node: 420*e3feb2ccSEmilio Cota * @tree: a #QTree 421*e3feb2ccSEmilio Cota * @key: the key to insert 422*e3feb2ccSEmilio Cota * @value: the value corresponding to the key 423*e3feb2ccSEmilio Cota * 424*e3feb2ccSEmilio Cota * Inserts a key/value pair into a #QTree. 425*e3feb2ccSEmilio Cota * 426*e3feb2ccSEmilio Cota * If the given key already exists in the #QTree its corresponding value 427*e3feb2ccSEmilio Cota * is set to the new value. If you supplied a @value_destroy_func when 428*e3feb2ccSEmilio Cota * creating the #QTree, the old value is freed using that function. If 429*e3feb2ccSEmilio Cota * you supplied a @key_destroy_func when creating the #QTree, the passed 430*e3feb2ccSEmilio Cota * key is freed using that function. 431*e3feb2ccSEmilio Cota * 432*e3feb2ccSEmilio Cota * The tree is automatically 'balanced' as new key/value pairs are added, 433*e3feb2ccSEmilio Cota * so that the distance from the root to every leaf is as small as possible. 434*e3feb2ccSEmilio Cota * The cost of maintaining a balanced tree while inserting new key/value 435*e3feb2ccSEmilio Cota * result in a O(n log(n)) operation where most of the other operations 436*e3feb2ccSEmilio Cota * are O(log(n)). 437*e3feb2ccSEmilio Cota * 438*e3feb2ccSEmilio Cota * Returns: (transfer none): the inserted (or set) node. 439*e3feb2ccSEmilio Cota * 440*e3feb2ccSEmilio Cota * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API. 441*e3feb2ccSEmilio Cota */ 442*e3feb2ccSEmilio Cota static QTreeNode * 443*e3feb2ccSEmilio Cota q_tree_insert_node(QTree *tree, 444*e3feb2ccSEmilio Cota gpointer key, 445*e3feb2ccSEmilio Cota gpointer value) 446*e3feb2ccSEmilio Cota { 447*e3feb2ccSEmilio Cota QTreeNode *node; 448*e3feb2ccSEmilio Cota 449*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, NULL); 450*e3feb2ccSEmilio Cota 451*e3feb2ccSEmilio Cota node = q_tree_insert_internal(tree, key, value, FALSE); 452*e3feb2ccSEmilio Cota 453*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 454*e3feb2ccSEmilio Cota q_tree_node_check(tree->root); 455*e3feb2ccSEmilio Cota #endif 456*e3feb2ccSEmilio Cota 457*e3feb2ccSEmilio Cota return node; 458*e3feb2ccSEmilio Cota } 459*e3feb2ccSEmilio Cota 460*e3feb2ccSEmilio Cota /** 461*e3feb2ccSEmilio Cota * q_tree_insert: 462*e3feb2ccSEmilio Cota * @tree: a #QTree 463*e3feb2ccSEmilio Cota * @key: the key to insert 464*e3feb2ccSEmilio Cota * @value: the value corresponding to the key 465*e3feb2ccSEmilio Cota * 466*e3feb2ccSEmilio Cota * Inserts a key/value pair into a #QTree. 467*e3feb2ccSEmilio Cota * 468*e3feb2ccSEmilio Cota * Inserts a new key and value into a #QTree as q_tree_insert_node() does, 469*e3feb2ccSEmilio Cota * only this function does not return the inserted or set node. 470*e3feb2ccSEmilio Cota */ 471*e3feb2ccSEmilio Cota void 472*e3feb2ccSEmilio Cota q_tree_insert(QTree *tree, 473*e3feb2ccSEmilio Cota gpointer key, 474*e3feb2ccSEmilio Cota gpointer value) 475*e3feb2ccSEmilio Cota { 476*e3feb2ccSEmilio Cota q_tree_insert_node(tree, key, value); 477*e3feb2ccSEmilio Cota } 478*e3feb2ccSEmilio Cota 479*e3feb2ccSEmilio Cota /** 480*e3feb2ccSEmilio Cota * q_tree_replace_node: 481*e3feb2ccSEmilio Cota * @tree: a #QTree 482*e3feb2ccSEmilio Cota * @key: the key to insert 483*e3feb2ccSEmilio Cota * @value: the value corresponding to the key 484*e3feb2ccSEmilio Cota * 485*e3feb2ccSEmilio Cota * Inserts a new key and value into a #QTree similar to q_tree_insert_node(). 486*e3feb2ccSEmilio Cota * The difference is that if the key already exists in the #QTree, it gets 487*e3feb2ccSEmilio Cota * replaced by the new key. If you supplied a @value_destroy_func when 488*e3feb2ccSEmilio Cota * creating the #QTree, the old value is freed using that function. If you 489*e3feb2ccSEmilio Cota * supplied a @key_destroy_func when creating the #QTree, the old key is 490*e3feb2ccSEmilio Cota * freed using that function. 491*e3feb2ccSEmilio Cota * 492*e3feb2ccSEmilio Cota * The tree is automatically 'balanced' as new key/value pairs are added, 493*e3feb2ccSEmilio Cota * so that the distance from the root to every leaf is as small as possible. 494*e3feb2ccSEmilio Cota * 495*e3feb2ccSEmilio Cota * Returns: (transfer none): the inserted (or set) node. 496*e3feb2ccSEmilio Cota * 497*e3feb2ccSEmilio Cota * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API. 498*e3feb2ccSEmilio Cota */ 499*e3feb2ccSEmilio Cota static QTreeNode * 500*e3feb2ccSEmilio Cota q_tree_replace_node(QTree *tree, 501*e3feb2ccSEmilio Cota gpointer key, 502*e3feb2ccSEmilio Cota gpointer value) 503*e3feb2ccSEmilio Cota { 504*e3feb2ccSEmilio Cota QTreeNode *node; 505*e3feb2ccSEmilio Cota 506*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, NULL); 507*e3feb2ccSEmilio Cota 508*e3feb2ccSEmilio Cota node = q_tree_insert_internal(tree, key, value, TRUE); 509*e3feb2ccSEmilio Cota 510*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 511*e3feb2ccSEmilio Cota q_tree_node_check(tree->root); 512*e3feb2ccSEmilio Cota #endif 513*e3feb2ccSEmilio Cota 514*e3feb2ccSEmilio Cota return node; 515*e3feb2ccSEmilio Cota } 516*e3feb2ccSEmilio Cota 517*e3feb2ccSEmilio Cota /** 518*e3feb2ccSEmilio Cota * q_tree_replace: 519*e3feb2ccSEmilio Cota * @tree: a #QTree 520*e3feb2ccSEmilio Cota * @key: the key to insert 521*e3feb2ccSEmilio Cota * @value: the value corresponding to the key 522*e3feb2ccSEmilio Cota * 523*e3feb2ccSEmilio Cota * Inserts a new key and value into a #QTree as q_tree_replace_node() does, 524*e3feb2ccSEmilio Cota * only this function does not return the inserted or set node. 525*e3feb2ccSEmilio Cota */ 526*e3feb2ccSEmilio Cota void 527*e3feb2ccSEmilio Cota q_tree_replace(QTree *tree, 528*e3feb2ccSEmilio Cota gpointer key, 529*e3feb2ccSEmilio Cota gpointer value) 530*e3feb2ccSEmilio Cota { 531*e3feb2ccSEmilio Cota q_tree_replace_node(tree, key, value); 532*e3feb2ccSEmilio Cota } 533*e3feb2ccSEmilio Cota 534*e3feb2ccSEmilio Cota /* internal insert routine */ 535*e3feb2ccSEmilio Cota static QTreeNode * 536*e3feb2ccSEmilio Cota q_tree_insert_internal(QTree *tree, 537*e3feb2ccSEmilio Cota gpointer key, 538*e3feb2ccSEmilio Cota gpointer value, 539*e3feb2ccSEmilio Cota gboolean replace) 540*e3feb2ccSEmilio Cota { 541*e3feb2ccSEmilio Cota QTreeNode *node, *retnode; 542*e3feb2ccSEmilio Cota QTreeNode *path[MAX_GTREE_HEIGHT]; 543*e3feb2ccSEmilio Cota int idx; 544*e3feb2ccSEmilio Cota 545*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, NULL); 546*e3feb2ccSEmilio Cota 547*e3feb2ccSEmilio Cota if (!tree->root) { 548*e3feb2ccSEmilio Cota tree->root = q_tree_node_new(key, value); 549*e3feb2ccSEmilio Cota tree->nnodes++; 550*e3feb2ccSEmilio Cota return tree->root; 551*e3feb2ccSEmilio Cota } 552*e3feb2ccSEmilio Cota 553*e3feb2ccSEmilio Cota idx = 0; 554*e3feb2ccSEmilio Cota path[idx++] = NULL; 555*e3feb2ccSEmilio Cota node = tree->root; 556*e3feb2ccSEmilio Cota 557*e3feb2ccSEmilio Cota while (1) { 558*e3feb2ccSEmilio Cota int cmp = tree->key_compare(key, node->key, tree->key_compare_data); 559*e3feb2ccSEmilio Cota 560*e3feb2ccSEmilio Cota if (cmp == 0) { 561*e3feb2ccSEmilio Cota if (tree->value_destroy_func) { 562*e3feb2ccSEmilio Cota tree->value_destroy_func(node->value); 563*e3feb2ccSEmilio Cota } 564*e3feb2ccSEmilio Cota 565*e3feb2ccSEmilio Cota node->value = value; 566*e3feb2ccSEmilio Cota 567*e3feb2ccSEmilio Cota if (replace) { 568*e3feb2ccSEmilio Cota if (tree->key_destroy_func) { 569*e3feb2ccSEmilio Cota tree->key_destroy_func(node->key); 570*e3feb2ccSEmilio Cota } 571*e3feb2ccSEmilio Cota 572*e3feb2ccSEmilio Cota node->key = key; 573*e3feb2ccSEmilio Cota } else { 574*e3feb2ccSEmilio Cota /* free the passed key */ 575*e3feb2ccSEmilio Cota if (tree->key_destroy_func) { 576*e3feb2ccSEmilio Cota tree->key_destroy_func(key); 577*e3feb2ccSEmilio Cota } 578*e3feb2ccSEmilio Cota } 579*e3feb2ccSEmilio Cota 580*e3feb2ccSEmilio Cota return node; 581*e3feb2ccSEmilio Cota } else if (cmp < 0) { 582*e3feb2ccSEmilio Cota if (node->left_child) { 583*e3feb2ccSEmilio Cota path[idx++] = node; 584*e3feb2ccSEmilio Cota node = node->left; 585*e3feb2ccSEmilio Cota } else { 586*e3feb2ccSEmilio Cota QTreeNode *child = q_tree_node_new(key, value); 587*e3feb2ccSEmilio Cota 588*e3feb2ccSEmilio Cota child->left = node->left; 589*e3feb2ccSEmilio Cota child->right = node; 590*e3feb2ccSEmilio Cota node->left = child; 591*e3feb2ccSEmilio Cota node->left_child = TRUE; 592*e3feb2ccSEmilio Cota node->balance -= 1; 593*e3feb2ccSEmilio Cota 594*e3feb2ccSEmilio Cota tree->nnodes++; 595*e3feb2ccSEmilio Cota 596*e3feb2ccSEmilio Cota retnode = child; 597*e3feb2ccSEmilio Cota break; 598*e3feb2ccSEmilio Cota } 599*e3feb2ccSEmilio Cota } else { 600*e3feb2ccSEmilio Cota if (node->right_child) { 601*e3feb2ccSEmilio Cota path[idx++] = node; 602*e3feb2ccSEmilio Cota node = node->right; 603*e3feb2ccSEmilio Cota } else { 604*e3feb2ccSEmilio Cota QTreeNode *child = q_tree_node_new(key, value); 605*e3feb2ccSEmilio Cota 606*e3feb2ccSEmilio Cota child->right = node->right; 607*e3feb2ccSEmilio Cota child->left = node; 608*e3feb2ccSEmilio Cota node->right = child; 609*e3feb2ccSEmilio Cota node->right_child = TRUE; 610*e3feb2ccSEmilio Cota node->balance += 1; 611*e3feb2ccSEmilio Cota 612*e3feb2ccSEmilio Cota tree->nnodes++; 613*e3feb2ccSEmilio Cota 614*e3feb2ccSEmilio Cota retnode = child; 615*e3feb2ccSEmilio Cota break; 616*e3feb2ccSEmilio Cota } 617*e3feb2ccSEmilio Cota } 618*e3feb2ccSEmilio Cota } 619*e3feb2ccSEmilio Cota 620*e3feb2ccSEmilio Cota /* 621*e3feb2ccSEmilio Cota * Restore balance. This is the goodness of a non-recursive 622*e3feb2ccSEmilio Cota * implementation, when we are done with balancing we 'break' 623*e3feb2ccSEmilio Cota * the loop and we are done. 624*e3feb2ccSEmilio Cota */ 625*e3feb2ccSEmilio Cota while (1) { 626*e3feb2ccSEmilio Cota QTreeNode *bparent = path[--idx]; 627*e3feb2ccSEmilio Cota gboolean left_node = (bparent && node == bparent->left); 628*e3feb2ccSEmilio Cota g_assert(!bparent || bparent->left == node || bparent->right == node); 629*e3feb2ccSEmilio Cota 630*e3feb2ccSEmilio Cota if (node->balance < -1 || node->balance > 1) { 631*e3feb2ccSEmilio Cota node = q_tree_node_balance(node); 632*e3feb2ccSEmilio Cota if (bparent == NULL) { 633*e3feb2ccSEmilio Cota tree->root = node; 634*e3feb2ccSEmilio Cota } else if (left_node) { 635*e3feb2ccSEmilio Cota bparent->left = node; 636*e3feb2ccSEmilio Cota } else { 637*e3feb2ccSEmilio Cota bparent->right = node; 638*e3feb2ccSEmilio Cota } 639*e3feb2ccSEmilio Cota } 640*e3feb2ccSEmilio Cota 641*e3feb2ccSEmilio Cota if (node->balance == 0 || bparent == NULL) { 642*e3feb2ccSEmilio Cota break; 643*e3feb2ccSEmilio Cota } 644*e3feb2ccSEmilio Cota 645*e3feb2ccSEmilio Cota if (left_node) { 646*e3feb2ccSEmilio Cota bparent->balance -= 1; 647*e3feb2ccSEmilio Cota } else { 648*e3feb2ccSEmilio Cota bparent->balance += 1; 649*e3feb2ccSEmilio Cota } 650*e3feb2ccSEmilio Cota 651*e3feb2ccSEmilio Cota node = bparent; 652*e3feb2ccSEmilio Cota } 653*e3feb2ccSEmilio Cota 654*e3feb2ccSEmilio Cota return retnode; 655*e3feb2ccSEmilio Cota } 656*e3feb2ccSEmilio Cota 657*e3feb2ccSEmilio Cota /** 658*e3feb2ccSEmilio Cota * q_tree_remove: 659*e3feb2ccSEmilio Cota * @tree: a #QTree 660*e3feb2ccSEmilio Cota * @key: the key to remove 661*e3feb2ccSEmilio Cota * 662*e3feb2ccSEmilio Cota * Removes a key/value pair from a #QTree. 663*e3feb2ccSEmilio Cota * 664*e3feb2ccSEmilio Cota * If the #QTree was created using q_tree_new_full(), the key and value 665*e3feb2ccSEmilio Cota * are freed using the supplied destroy functions, otherwise you have to 666*e3feb2ccSEmilio Cota * make sure that any dynamically allocated values are freed yourself. 667*e3feb2ccSEmilio Cota * If the key does not exist in the #QTree, the function does nothing. 668*e3feb2ccSEmilio Cota * 669*e3feb2ccSEmilio Cota * The cost of maintaining a balanced tree while removing a key/value 670*e3feb2ccSEmilio Cota * result in a O(n log(n)) operation where most of the other operations 671*e3feb2ccSEmilio Cota * are O(log(n)). 672*e3feb2ccSEmilio Cota * 673*e3feb2ccSEmilio Cota * Returns: %TRUE if the key was found (prior to 2.8, this function 674*e3feb2ccSEmilio Cota * returned nothing) 675*e3feb2ccSEmilio Cota */ 676*e3feb2ccSEmilio Cota gboolean 677*e3feb2ccSEmilio Cota q_tree_remove(QTree *tree, 678*e3feb2ccSEmilio Cota gconstpointer key) 679*e3feb2ccSEmilio Cota { 680*e3feb2ccSEmilio Cota gboolean removed; 681*e3feb2ccSEmilio Cota 682*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, FALSE); 683*e3feb2ccSEmilio Cota 684*e3feb2ccSEmilio Cota removed = q_tree_remove_internal(tree, key, FALSE); 685*e3feb2ccSEmilio Cota 686*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 687*e3feb2ccSEmilio Cota q_tree_node_check(tree->root); 688*e3feb2ccSEmilio Cota #endif 689*e3feb2ccSEmilio Cota 690*e3feb2ccSEmilio Cota return removed; 691*e3feb2ccSEmilio Cota } 692*e3feb2ccSEmilio Cota 693*e3feb2ccSEmilio Cota /** 694*e3feb2ccSEmilio Cota * q_tree_steal: 695*e3feb2ccSEmilio Cota * @tree: a #QTree 696*e3feb2ccSEmilio Cota * @key: the key to remove 697*e3feb2ccSEmilio Cota * 698*e3feb2ccSEmilio Cota * Removes a key and its associated value from a #QTree without calling 699*e3feb2ccSEmilio Cota * the key and value destroy functions. 700*e3feb2ccSEmilio Cota * 701*e3feb2ccSEmilio Cota * If the key does not exist in the #QTree, the function does nothing. 702*e3feb2ccSEmilio Cota * 703*e3feb2ccSEmilio Cota * Returns: %TRUE if the key was found (prior to 2.8, this function 704*e3feb2ccSEmilio Cota * returned nothing) 705*e3feb2ccSEmilio Cota */ 706*e3feb2ccSEmilio Cota gboolean 707*e3feb2ccSEmilio Cota q_tree_steal(QTree *tree, 708*e3feb2ccSEmilio Cota gconstpointer key) 709*e3feb2ccSEmilio Cota { 710*e3feb2ccSEmilio Cota gboolean removed; 711*e3feb2ccSEmilio Cota 712*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, FALSE); 713*e3feb2ccSEmilio Cota 714*e3feb2ccSEmilio Cota removed = q_tree_remove_internal(tree, key, TRUE); 715*e3feb2ccSEmilio Cota 716*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 717*e3feb2ccSEmilio Cota q_tree_node_check(tree->root); 718*e3feb2ccSEmilio Cota #endif 719*e3feb2ccSEmilio Cota 720*e3feb2ccSEmilio Cota return removed; 721*e3feb2ccSEmilio Cota } 722*e3feb2ccSEmilio Cota 723*e3feb2ccSEmilio Cota /* internal remove routine */ 724*e3feb2ccSEmilio Cota static gboolean 725*e3feb2ccSEmilio Cota q_tree_remove_internal(QTree *tree, 726*e3feb2ccSEmilio Cota gconstpointer key, 727*e3feb2ccSEmilio Cota gboolean steal) 728*e3feb2ccSEmilio Cota { 729*e3feb2ccSEmilio Cota QTreeNode *node, *parent, *balance; 730*e3feb2ccSEmilio Cota QTreeNode *path[MAX_GTREE_HEIGHT]; 731*e3feb2ccSEmilio Cota int idx; 732*e3feb2ccSEmilio Cota gboolean left_node; 733*e3feb2ccSEmilio Cota 734*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, FALSE); 735*e3feb2ccSEmilio Cota 736*e3feb2ccSEmilio Cota if (!tree->root) { 737*e3feb2ccSEmilio Cota return FALSE; 738*e3feb2ccSEmilio Cota } 739*e3feb2ccSEmilio Cota 740*e3feb2ccSEmilio Cota idx = 0; 741*e3feb2ccSEmilio Cota path[idx++] = NULL; 742*e3feb2ccSEmilio Cota node = tree->root; 743*e3feb2ccSEmilio Cota 744*e3feb2ccSEmilio Cota while (1) { 745*e3feb2ccSEmilio Cota int cmp = tree->key_compare(key, node->key, tree->key_compare_data); 746*e3feb2ccSEmilio Cota 747*e3feb2ccSEmilio Cota if (cmp == 0) { 748*e3feb2ccSEmilio Cota break; 749*e3feb2ccSEmilio Cota } else if (cmp < 0) { 750*e3feb2ccSEmilio Cota if (!node->left_child) { 751*e3feb2ccSEmilio Cota return FALSE; 752*e3feb2ccSEmilio Cota } 753*e3feb2ccSEmilio Cota 754*e3feb2ccSEmilio Cota path[idx++] = node; 755*e3feb2ccSEmilio Cota node = node->left; 756*e3feb2ccSEmilio Cota } else { 757*e3feb2ccSEmilio Cota if (!node->right_child) { 758*e3feb2ccSEmilio Cota return FALSE; 759*e3feb2ccSEmilio Cota } 760*e3feb2ccSEmilio Cota 761*e3feb2ccSEmilio Cota path[idx++] = node; 762*e3feb2ccSEmilio Cota node = node->right; 763*e3feb2ccSEmilio Cota } 764*e3feb2ccSEmilio Cota } 765*e3feb2ccSEmilio Cota 766*e3feb2ccSEmilio Cota /* 767*e3feb2ccSEmilio Cota * The following code is almost equal to q_tree_remove_node, 768*e3feb2ccSEmilio Cota * except that we do not have to call q_tree_node_parent. 769*e3feb2ccSEmilio Cota */ 770*e3feb2ccSEmilio Cota balance = parent = path[--idx]; 771*e3feb2ccSEmilio Cota g_assert(!parent || parent->left == node || parent->right == node); 772*e3feb2ccSEmilio Cota left_node = (parent && node == parent->left); 773*e3feb2ccSEmilio Cota 774*e3feb2ccSEmilio Cota if (!node->left_child) { 775*e3feb2ccSEmilio Cota if (!node->right_child) { 776*e3feb2ccSEmilio Cota if (!parent) { 777*e3feb2ccSEmilio Cota tree->root = NULL; 778*e3feb2ccSEmilio Cota } else if (left_node) { 779*e3feb2ccSEmilio Cota parent->left_child = FALSE; 780*e3feb2ccSEmilio Cota parent->left = node->left; 781*e3feb2ccSEmilio Cota parent->balance += 1; 782*e3feb2ccSEmilio Cota } else { 783*e3feb2ccSEmilio Cota parent->right_child = FALSE; 784*e3feb2ccSEmilio Cota parent->right = node->right; 785*e3feb2ccSEmilio Cota parent->balance -= 1; 786*e3feb2ccSEmilio Cota } 787*e3feb2ccSEmilio Cota } else { 788*e3feb2ccSEmilio Cota /* node has a right child */ 789*e3feb2ccSEmilio Cota QTreeNode *tmp = q_tree_node_next(node); 790*e3feb2ccSEmilio Cota tmp->left = node->left; 791*e3feb2ccSEmilio Cota 792*e3feb2ccSEmilio Cota if (!parent) { 793*e3feb2ccSEmilio Cota tree->root = node->right; 794*e3feb2ccSEmilio Cota } else if (left_node) { 795*e3feb2ccSEmilio Cota parent->left = node->right; 796*e3feb2ccSEmilio Cota parent->balance += 1; 797*e3feb2ccSEmilio Cota } else { 798*e3feb2ccSEmilio Cota parent->right = node->right; 799*e3feb2ccSEmilio Cota parent->balance -= 1; 800*e3feb2ccSEmilio Cota } 801*e3feb2ccSEmilio Cota } 802*e3feb2ccSEmilio Cota } else { 803*e3feb2ccSEmilio Cota /* node has a left child */ 804*e3feb2ccSEmilio Cota if (!node->right_child) { 805*e3feb2ccSEmilio Cota QTreeNode *tmp = q_tree_node_previous(node); 806*e3feb2ccSEmilio Cota tmp->right = node->right; 807*e3feb2ccSEmilio Cota 808*e3feb2ccSEmilio Cota if (parent == NULL) { 809*e3feb2ccSEmilio Cota tree->root = node->left; 810*e3feb2ccSEmilio Cota } else if (left_node) { 811*e3feb2ccSEmilio Cota parent->left = node->left; 812*e3feb2ccSEmilio Cota parent->balance += 1; 813*e3feb2ccSEmilio Cota } else { 814*e3feb2ccSEmilio Cota parent->right = node->left; 815*e3feb2ccSEmilio Cota parent->balance -= 1; 816*e3feb2ccSEmilio Cota } 817*e3feb2ccSEmilio Cota } else { 818*e3feb2ccSEmilio Cota /* node has a both children (pant, pant!) */ 819*e3feb2ccSEmilio Cota QTreeNode *prev = node->left; 820*e3feb2ccSEmilio Cota QTreeNode *next = node->right; 821*e3feb2ccSEmilio Cota QTreeNode *nextp = node; 822*e3feb2ccSEmilio Cota int old_idx = idx + 1; 823*e3feb2ccSEmilio Cota idx++; 824*e3feb2ccSEmilio Cota 825*e3feb2ccSEmilio Cota /* path[idx] == parent */ 826*e3feb2ccSEmilio Cota /* find the immediately next node (and its parent) */ 827*e3feb2ccSEmilio Cota while (next->left_child) { 828*e3feb2ccSEmilio Cota path[++idx] = nextp = next; 829*e3feb2ccSEmilio Cota next = next->left; 830*e3feb2ccSEmilio Cota } 831*e3feb2ccSEmilio Cota 832*e3feb2ccSEmilio Cota path[old_idx] = next; 833*e3feb2ccSEmilio Cota balance = path[idx]; 834*e3feb2ccSEmilio Cota 835*e3feb2ccSEmilio Cota /* remove 'next' from the tree */ 836*e3feb2ccSEmilio Cota if (nextp != node) { 837*e3feb2ccSEmilio Cota if (next->right_child) { 838*e3feb2ccSEmilio Cota nextp->left = next->right; 839*e3feb2ccSEmilio Cota } else { 840*e3feb2ccSEmilio Cota nextp->left_child = FALSE; 841*e3feb2ccSEmilio Cota } 842*e3feb2ccSEmilio Cota nextp->balance += 1; 843*e3feb2ccSEmilio Cota 844*e3feb2ccSEmilio Cota next->right_child = TRUE; 845*e3feb2ccSEmilio Cota next->right = node->right; 846*e3feb2ccSEmilio Cota } else { 847*e3feb2ccSEmilio Cota node->balance -= 1; 848*e3feb2ccSEmilio Cota } 849*e3feb2ccSEmilio Cota 850*e3feb2ccSEmilio Cota /* set the prev to point to the right place */ 851*e3feb2ccSEmilio Cota while (prev->right_child) { 852*e3feb2ccSEmilio Cota prev = prev->right; 853*e3feb2ccSEmilio Cota } 854*e3feb2ccSEmilio Cota prev->right = next; 855*e3feb2ccSEmilio Cota 856*e3feb2ccSEmilio Cota /* prepare 'next' to replace 'node' */ 857*e3feb2ccSEmilio Cota next->left_child = TRUE; 858*e3feb2ccSEmilio Cota next->left = node->left; 859*e3feb2ccSEmilio Cota next->balance = node->balance; 860*e3feb2ccSEmilio Cota 861*e3feb2ccSEmilio Cota if (!parent) { 862*e3feb2ccSEmilio Cota tree->root = next; 863*e3feb2ccSEmilio Cota } else if (left_node) { 864*e3feb2ccSEmilio Cota parent->left = next; 865*e3feb2ccSEmilio Cota } else { 866*e3feb2ccSEmilio Cota parent->right = next; 867*e3feb2ccSEmilio Cota } 868*e3feb2ccSEmilio Cota } 869*e3feb2ccSEmilio Cota } 870*e3feb2ccSEmilio Cota 871*e3feb2ccSEmilio Cota /* restore balance */ 872*e3feb2ccSEmilio Cota if (balance) { 873*e3feb2ccSEmilio Cota while (1) { 874*e3feb2ccSEmilio Cota QTreeNode *bparent = path[--idx]; 875*e3feb2ccSEmilio Cota g_assert(!bparent || 876*e3feb2ccSEmilio Cota bparent->left == balance || 877*e3feb2ccSEmilio Cota bparent->right == balance); 878*e3feb2ccSEmilio Cota left_node = (bparent && balance == bparent->left); 879*e3feb2ccSEmilio Cota 880*e3feb2ccSEmilio Cota if (balance->balance < -1 || balance->balance > 1) { 881*e3feb2ccSEmilio Cota balance = q_tree_node_balance(balance); 882*e3feb2ccSEmilio Cota if (!bparent) { 883*e3feb2ccSEmilio Cota tree->root = balance; 884*e3feb2ccSEmilio Cota } else if (left_node) { 885*e3feb2ccSEmilio Cota bparent->left = balance; 886*e3feb2ccSEmilio Cota } else { 887*e3feb2ccSEmilio Cota bparent->right = balance; 888*e3feb2ccSEmilio Cota } 889*e3feb2ccSEmilio Cota } 890*e3feb2ccSEmilio Cota 891*e3feb2ccSEmilio Cota if (balance->balance != 0 || !bparent) { 892*e3feb2ccSEmilio Cota break; 893*e3feb2ccSEmilio Cota } 894*e3feb2ccSEmilio Cota 895*e3feb2ccSEmilio Cota if (left_node) { 896*e3feb2ccSEmilio Cota bparent->balance += 1; 897*e3feb2ccSEmilio Cota } else { 898*e3feb2ccSEmilio Cota bparent->balance -= 1; 899*e3feb2ccSEmilio Cota } 900*e3feb2ccSEmilio Cota 901*e3feb2ccSEmilio Cota balance = bparent; 902*e3feb2ccSEmilio Cota } 903*e3feb2ccSEmilio Cota } 904*e3feb2ccSEmilio Cota 905*e3feb2ccSEmilio Cota if (!steal) { 906*e3feb2ccSEmilio Cota if (tree->key_destroy_func) { 907*e3feb2ccSEmilio Cota tree->key_destroy_func(node->key); 908*e3feb2ccSEmilio Cota } 909*e3feb2ccSEmilio Cota if (tree->value_destroy_func) { 910*e3feb2ccSEmilio Cota tree->value_destroy_func(node->value); 911*e3feb2ccSEmilio Cota } 912*e3feb2ccSEmilio Cota } 913*e3feb2ccSEmilio Cota 914*e3feb2ccSEmilio Cota g_free(node); 915*e3feb2ccSEmilio Cota 916*e3feb2ccSEmilio Cota tree->nnodes--; 917*e3feb2ccSEmilio Cota 918*e3feb2ccSEmilio Cota return TRUE; 919*e3feb2ccSEmilio Cota } 920*e3feb2ccSEmilio Cota 921*e3feb2ccSEmilio Cota /** 922*e3feb2ccSEmilio Cota * q_tree_lookup_node: 923*e3feb2ccSEmilio Cota * @tree: a #QTree 924*e3feb2ccSEmilio Cota * @key: the key to look up 925*e3feb2ccSEmilio Cota * 926*e3feb2ccSEmilio Cota * Gets the tree node corresponding to the given key. Since a #QTree is 927*e3feb2ccSEmilio Cota * automatically balanced as key/value pairs are added, key lookup 928*e3feb2ccSEmilio Cota * is O(log n) (where n is the number of key/value pairs in the tree). 929*e3feb2ccSEmilio Cota * 930*e3feb2ccSEmilio Cota * Returns: (nullable) (transfer none): the tree node corresponding to 931*e3feb2ccSEmilio Cota * the key, or %NULL if the key was not found 932*e3feb2ccSEmilio Cota * 933*e3feb2ccSEmilio Cota * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API. 934*e3feb2ccSEmilio Cota */ 935*e3feb2ccSEmilio Cota static QTreeNode * 936*e3feb2ccSEmilio Cota q_tree_lookup_node(QTree *tree, 937*e3feb2ccSEmilio Cota gconstpointer key) 938*e3feb2ccSEmilio Cota { 939*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, NULL); 940*e3feb2ccSEmilio Cota 941*e3feb2ccSEmilio Cota return q_tree_find_node(tree, key); 942*e3feb2ccSEmilio Cota } 943*e3feb2ccSEmilio Cota 944*e3feb2ccSEmilio Cota /** 945*e3feb2ccSEmilio Cota * q_tree_lookup: 946*e3feb2ccSEmilio Cota * @tree: a #QTree 947*e3feb2ccSEmilio Cota * @key: the key to look up 948*e3feb2ccSEmilio Cota * 949*e3feb2ccSEmilio Cota * Gets the value corresponding to the given key. Since a #QTree is 950*e3feb2ccSEmilio Cota * automatically balanced as key/value pairs are added, key lookup 951*e3feb2ccSEmilio Cota * is O(log n) (where n is the number of key/value pairs in the tree). 952*e3feb2ccSEmilio Cota * 953*e3feb2ccSEmilio Cota * Returns: the value corresponding to the key, or %NULL 954*e3feb2ccSEmilio Cota * if the key was not found 955*e3feb2ccSEmilio Cota */ 956*e3feb2ccSEmilio Cota gpointer 957*e3feb2ccSEmilio Cota q_tree_lookup(QTree *tree, 958*e3feb2ccSEmilio Cota gconstpointer key) 959*e3feb2ccSEmilio Cota { 960*e3feb2ccSEmilio Cota QTreeNode *node; 961*e3feb2ccSEmilio Cota 962*e3feb2ccSEmilio Cota node = q_tree_lookup_node(tree, key); 963*e3feb2ccSEmilio Cota 964*e3feb2ccSEmilio Cota return node ? node->value : NULL; 965*e3feb2ccSEmilio Cota } 966*e3feb2ccSEmilio Cota 967*e3feb2ccSEmilio Cota /** 968*e3feb2ccSEmilio Cota * q_tree_lookup_extended: 969*e3feb2ccSEmilio Cota * @tree: a #QTree 970*e3feb2ccSEmilio Cota * @lookup_key: the key to look up 971*e3feb2ccSEmilio Cota * @orig_key: (out) (optional) (nullable): returns the original key 972*e3feb2ccSEmilio Cota * @value: (out) (optional) (nullable): returns the value associated with 973*e3feb2ccSEmilio Cota * the key 974*e3feb2ccSEmilio Cota * 975*e3feb2ccSEmilio Cota * Looks up a key in the #QTree, returning the original key and the 976*e3feb2ccSEmilio Cota * associated value. This is useful if you need to free the memory 977*e3feb2ccSEmilio Cota * allocated for the original key, for example before calling 978*e3feb2ccSEmilio Cota * q_tree_remove(). 979*e3feb2ccSEmilio Cota * 980*e3feb2ccSEmilio Cota * Returns: %TRUE if the key was found in the #QTree 981*e3feb2ccSEmilio Cota */ 982*e3feb2ccSEmilio Cota gboolean 983*e3feb2ccSEmilio Cota q_tree_lookup_extended(QTree *tree, 984*e3feb2ccSEmilio Cota gconstpointer lookup_key, 985*e3feb2ccSEmilio Cota gpointer *orig_key, 986*e3feb2ccSEmilio Cota gpointer *value) 987*e3feb2ccSEmilio Cota { 988*e3feb2ccSEmilio Cota QTreeNode *node; 989*e3feb2ccSEmilio Cota 990*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, FALSE); 991*e3feb2ccSEmilio Cota 992*e3feb2ccSEmilio Cota node = q_tree_find_node(tree, lookup_key); 993*e3feb2ccSEmilio Cota 994*e3feb2ccSEmilio Cota if (node) { 995*e3feb2ccSEmilio Cota if (orig_key) { 996*e3feb2ccSEmilio Cota *orig_key = node->key; 997*e3feb2ccSEmilio Cota } 998*e3feb2ccSEmilio Cota if (value) { 999*e3feb2ccSEmilio Cota *value = node->value; 1000*e3feb2ccSEmilio Cota } 1001*e3feb2ccSEmilio Cota return TRUE; 1002*e3feb2ccSEmilio Cota } else { 1003*e3feb2ccSEmilio Cota return FALSE; 1004*e3feb2ccSEmilio Cota } 1005*e3feb2ccSEmilio Cota } 1006*e3feb2ccSEmilio Cota 1007*e3feb2ccSEmilio Cota /** 1008*e3feb2ccSEmilio Cota * q_tree_foreach: 1009*e3feb2ccSEmilio Cota * @tree: a #QTree 1010*e3feb2ccSEmilio Cota * @func: the function to call for each node visited. 1011*e3feb2ccSEmilio Cota * If this function returns %TRUE, the traversal is stopped. 1012*e3feb2ccSEmilio Cota * @user_data: user data to pass to the function 1013*e3feb2ccSEmilio Cota * 1014*e3feb2ccSEmilio Cota * Calls the given function for each of the key/value pairs in the #QTree. 1015*e3feb2ccSEmilio Cota * The function is passed the key and value of each pair, and the given 1016*e3feb2ccSEmilio Cota * @data parameter. The tree is traversed in sorted order. 1017*e3feb2ccSEmilio Cota * 1018*e3feb2ccSEmilio Cota * The tree may not be modified while iterating over it (you can't 1019*e3feb2ccSEmilio Cota * add/remove items). To remove all items matching a predicate, you need 1020*e3feb2ccSEmilio Cota * to add each item to a list in your #GTraverseFunc as you walk over 1021*e3feb2ccSEmilio Cota * the tree, then walk the list and remove each item. 1022*e3feb2ccSEmilio Cota */ 1023*e3feb2ccSEmilio Cota void 1024*e3feb2ccSEmilio Cota q_tree_foreach(QTree *tree, 1025*e3feb2ccSEmilio Cota GTraverseFunc func, 1026*e3feb2ccSEmilio Cota gpointer user_data) 1027*e3feb2ccSEmilio Cota { 1028*e3feb2ccSEmilio Cota QTreeNode *node; 1029*e3feb2ccSEmilio Cota 1030*e3feb2ccSEmilio Cota g_return_if_fail(tree != NULL); 1031*e3feb2ccSEmilio Cota 1032*e3feb2ccSEmilio Cota if (!tree->root) { 1033*e3feb2ccSEmilio Cota return; 1034*e3feb2ccSEmilio Cota } 1035*e3feb2ccSEmilio Cota 1036*e3feb2ccSEmilio Cota node = q_tree_node_first(tree); 1037*e3feb2ccSEmilio Cota 1038*e3feb2ccSEmilio Cota while (node) { 1039*e3feb2ccSEmilio Cota if ((*func)(node->key, node->value, user_data)) { 1040*e3feb2ccSEmilio Cota break; 1041*e3feb2ccSEmilio Cota } 1042*e3feb2ccSEmilio Cota 1043*e3feb2ccSEmilio Cota node = q_tree_node_next(node); 1044*e3feb2ccSEmilio Cota } 1045*e3feb2ccSEmilio Cota } 1046*e3feb2ccSEmilio Cota 1047*e3feb2ccSEmilio Cota /** 1048*e3feb2ccSEmilio Cota * q_tree_search_node: 1049*e3feb2ccSEmilio Cota * @tree: a #QTree 1050*e3feb2ccSEmilio Cota * @search_func: a function used to search the #QTree 1051*e3feb2ccSEmilio Cota * @user_data: the data passed as the second argument to @search_func 1052*e3feb2ccSEmilio Cota * 1053*e3feb2ccSEmilio Cota * Searches a #QTree using @search_func. 1054*e3feb2ccSEmilio Cota * 1055*e3feb2ccSEmilio Cota * The @search_func is called with a pointer to the key of a key/value 1056*e3feb2ccSEmilio Cota * pair in the tree, and the passed in @user_data. If @search_func returns 1057*e3feb2ccSEmilio Cota * 0 for a key/value pair, then the corresponding node is returned as 1058*e3feb2ccSEmilio Cota * the result of q_tree_search(). If @search_func returns -1, searching 1059*e3feb2ccSEmilio Cota * will proceed among the key/value pairs that have a smaller key; if 1060*e3feb2ccSEmilio Cota * @search_func returns 1, searching will proceed among the key/value 1061*e3feb2ccSEmilio Cota * pairs that have a larger key. 1062*e3feb2ccSEmilio Cota * 1063*e3feb2ccSEmilio Cota * Returns: (nullable) (transfer none): the node corresponding to the 1064*e3feb2ccSEmilio Cota * found key, or %NULL if the key was not found 1065*e3feb2ccSEmilio Cota * 1066*e3feb2ccSEmilio Cota * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API. 1067*e3feb2ccSEmilio Cota */ 1068*e3feb2ccSEmilio Cota static QTreeNode * 1069*e3feb2ccSEmilio Cota q_tree_search_node(QTree *tree, 1070*e3feb2ccSEmilio Cota GCompareFunc search_func, 1071*e3feb2ccSEmilio Cota gconstpointer user_data) 1072*e3feb2ccSEmilio Cota { 1073*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, NULL); 1074*e3feb2ccSEmilio Cota 1075*e3feb2ccSEmilio Cota if (!tree->root) { 1076*e3feb2ccSEmilio Cota return NULL; 1077*e3feb2ccSEmilio Cota } 1078*e3feb2ccSEmilio Cota 1079*e3feb2ccSEmilio Cota return q_tree_node_search(tree->root, search_func, user_data); 1080*e3feb2ccSEmilio Cota } 1081*e3feb2ccSEmilio Cota 1082*e3feb2ccSEmilio Cota /** 1083*e3feb2ccSEmilio Cota * q_tree_search: 1084*e3feb2ccSEmilio Cota * @tree: a #QTree 1085*e3feb2ccSEmilio Cota * @search_func: a function used to search the #QTree 1086*e3feb2ccSEmilio Cota * @user_data: the data passed as the second argument to @search_func 1087*e3feb2ccSEmilio Cota * 1088*e3feb2ccSEmilio Cota * Searches a #QTree using @search_func. 1089*e3feb2ccSEmilio Cota * 1090*e3feb2ccSEmilio Cota * The @search_func is called with a pointer to the key of a key/value 1091*e3feb2ccSEmilio Cota * pair in the tree, and the passed in @user_data. If @search_func returns 1092*e3feb2ccSEmilio Cota * 0 for a key/value pair, then the corresponding value is returned as 1093*e3feb2ccSEmilio Cota * the result of q_tree_search(). If @search_func returns -1, searching 1094*e3feb2ccSEmilio Cota * will proceed among the key/value pairs that have a smaller key; if 1095*e3feb2ccSEmilio Cota * @search_func returns 1, searching will proceed among the key/value 1096*e3feb2ccSEmilio Cota * pairs that have a larger key. 1097*e3feb2ccSEmilio Cota * 1098*e3feb2ccSEmilio Cota * Returns: the value corresponding to the found key, or %NULL 1099*e3feb2ccSEmilio Cota * if the key was not found 1100*e3feb2ccSEmilio Cota */ 1101*e3feb2ccSEmilio Cota gpointer 1102*e3feb2ccSEmilio Cota q_tree_search(QTree *tree, 1103*e3feb2ccSEmilio Cota GCompareFunc search_func, 1104*e3feb2ccSEmilio Cota gconstpointer user_data) 1105*e3feb2ccSEmilio Cota { 1106*e3feb2ccSEmilio Cota QTreeNode *node; 1107*e3feb2ccSEmilio Cota 1108*e3feb2ccSEmilio Cota node = q_tree_search_node(tree, search_func, user_data); 1109*e3feb2ccSEmilio Cota 1110*e3feb2ccSEmilio Cota return node ? node->value : NULL; 1111*e3feb2ccSEmilio Cota } 1112*e3feb2ccSEmilio Cota 1113*e3feb2ccSEmilio Cota /** 1114*e3feb2ccSEmilio Cota * q_tree_height: 1115*e3feb2ccSEmilio Cota * @tree: a #QTree 1116*e3feb2ccSEmilio Cota * 1117*e3feb2ccSEmilio Cota * Gets the height of a #QTree. 1118*e3feb2ccSEmilio Cota * 1119*e3feb2ccSEmilio Cota * If the #QTree contains no nodes, the height is 0. 1120*e3feb2ccSEmilio Cota * If the #QTree contains only one root node the height is 1. 1121*e3feb2ccSEmilio Cota * If the root node has children the height is 2, etc. 1122*e3feb2ccSEmilio Cota * 1123*e3feb2ccSEmilio Cota * Returns: the height of @tree 1124*e3feb2ccSEmilio Cota */ 1125*e3feb2ccSEmilio Cota gint 1126*e3feb2ccSEmilio Cota q_tree_height(QTree *tree) 1127*e3feb2ccSEmilio Cota { 1128*e3feb2ccSEmilio Cota QTreeNode *node; 1129*e3feb2ccSEmilio Cota gint height; 1130*e3feb2ccSEmilio Cota 1131*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, 0); 1132*e3feb2ccSEmilio Cota 1133*e3feb2ccSEmilio Cota if (!tree->root) { 1134*e3feb2ccSEmilio Cota return 0; 1135*e3feb2ccSEmilio Cota } 1136*e3feb2ccSEmilio Cota 1137*e3feb2ccSEmilio Cota height = 0; 1138*e3feb2ccSEmilio Cota node = tree->root; 1139*e3feb2ccSEmilio Cota 1140*e3feb2ccSEmilio Cota while (1) { 1141*e3feb2ccSEmilio Cota height += 1 + MAX(node->balance, 0); 1142*e3feb2ccSEmilio Cota 1143*e3feb2ccSEmilio Cota if (!node->left_child) { 1144*e3feb2ccSEmilio Cota return height; 1145*e3feb2ccSEmilio Cota } 1146*e3feb2ccSEmilio Cota 1147*e3feb2ccSEmilio Cota node = node->left; 1148*e3feb2ccSEmilio Cota } 1149*e3feb2ccSEmilio Cota } 1150*e3feb2ccSEmilio Cota 1151*e3feb2ccSEmilio Cota /** 1152*e3feb2ccSEmilio Cota * q_tree_nnodes: 1153*e3feb2ccSEmilio Cota * @tree: a #QTree 1154*e3feb2ccSEmilio Cota * 1155*e3feb2ccSEmilio Cota * Gets the number of nodes in a #QTree. 1156*e3feb2ccSEmilio Cota * 1157*e3feb2ccSEmilio Cota * Returns: the number of nodes in @tree 1158*e3feb2ccSEmilio Cota */ 1159*e3feb2ccSEmilio Cota gint 1160*e3feb2ccSEmilio Cota q_tree_nnodes(QTree *tree) 1161*e3feb2ccSEmilio Cota { 1162*e3feb2ccSEmilio Cota g_return_val_if_fail(tree != NULL, 0); 1163*e3feb2ccSEmilio Cota 1164*e3feb2ccSEmilio Cota return tree->nnodes; 1165*e3feb2ccSEmilio Cota } 1166*e3feb2ccSEmilio Cota 1167*e3feb2ccSEmilio Cota static QTreeNode * 1168*e3feb2ccSEmilio Cota q_tree_node_balance(QTreeNode *node) 1169*e3feb2ccSEmilio Cota { 1170*e3feb2ccSEmilio Cota if (node->balance < -1) { 1171*e3feb2ccSEmilio Cota if (node->left->balance > 0) { 1172*e3feb2ccSEmilio Cota node->left = q_tree_node_rotate_left(node->left); 1173*e3feb2ccSEmilio Cota } 1174*e3feb2ccSEmilio Cota node = q_tree_node_rotate_right(node); 1175*e3feb2ccSEmilio Cota } else if (node->balance > 1) { 1176*e3feb2ccSEmilio Cota if (node->right->balance < 0) { 1177*e3feb2ccSEmilio Cota node->right = q_tree_node_rotate_right(node->right); 1178*e3feb2ccSEmilio Cota } 1179*e3feb2ccSEmilio Cota node = q_tree_node_rotate_left(node); 1180*e3feb2ccSEmilio Cota } 1181*e3feb2ccSEmilio Cota 1182*e3feb2ccSEmilio Cota return node; 1183*e3feb2ccSEmilio Cota } 1184*e3feb2ccSEmilio Cota 1185*e3feb2ccSEmilio Cota static QTreeNode * 1186*e3feb2ccSEmilio Cota q_tree_find_node(QTree *tree, 1187*e3feb2ccSEmilio Cota gconstpointer key) 1188*e3feb2ccSEmilio Cota { 1189*e3feb2ccSEmilio Cota QTreeNode *node; 1190*e3feb2ccSEmilio Cota gint cmp; 1191*e3feb2ccSEmilio Cota 1192*e3feb2ccSEmilio Cota node = tree->root; 1193*e3feb2ccSEmilio Cota if (!node) { 1194*e3feb2ccSEmilio Cota return NULL; 1195*e3feb2ccSEmilio Cota } 1196*e3feb2ccSEmilio Cota 1197*e3feb2ccSEmilio Cota while (1) { 1198*e3feb2ccSEmilio Cota cmp = tree->key_compare(key, node->key, tree->key_compare_data); 1199*e3feb2ccSEmilio Cota if (cmp == 0) { 1200*e3feb2ccSEmilio Cota return node; 1201*e3feb2ccSEmilio Cota } else if (cmp < 0) { 1202*e3feb2ccSEmilio Cota if (!node->left_child) { 1203*e3feb2ccSEmilio Cota return NULL; 1204*e3feb2ccSEmilio Cota } 1205*e3feb2ccSEmilio Cota 1206*e3feb2ccSEmilio Cota node = node->left; 1207*e3feb2ccSEmilio Cota } else { 1208*e3feb2ccSEmilio Cota if (!node->right_child) { 1209*e3feb2ccSEmilio Cota return NULL; 1210*e3feb2ccSEmilio Cota } 1211*e3feb2ccSEmilio Cota 1212*e3feb2ccSEmilio Cota node = node->right; 1213*e3feb2ccSEmilio Cota } 1214*e3feb2ccSEmilio Cota } 1215*e3feb2ccSEmilio Cota } 1216*e3feb2ccSEmilio Cota 1217*e3feb2ccSEmilio Cota static QTreeNode * 1218*e3feb2ccSEmilio Cota q_tree_node_search(QTreeNode *node, 1219*e3feb2ccSEmilio Cota GCompareFunc search_func, 1220*e3feb2ccSEmilio Cota gconstpointer data) 1221*e3feb2ccSEmilio Cota { 1222*e3feb2ccSEmilio Cota gint dir; 1223*e3feb2ccSEmilio Cota 1224*e3feb2ccSEmilio Cota if (!node) { 1225*e3feb2ccSEmilio Cota return NULL; 1226*e3feb2ccSEmilio Cota } 1227*e3feb2ccSEmilio Cota 1228*e3feb2ccSEmilio Cota while (1) { 1229*e3feb2ccSEmilio Cota dir = (*search_func)(node->key, data); 1230*e3feb2ccSEmilio Cota if (dir == 0) { 1231*e3feb2ccSEmilio Cota return node; 1232*e3feb2ccSEmilio Cota } else if (dir < 0) { 1233*e3feb2ccSEmilio Cota if (!node->left_child) { 1234*e3feb2ccSEmilio Cota return NULL; 1235*e3feb2ccSEmilio Cota } 1236*e3feb2ccSEmilio Cota 1237*e3feb2ccSEmilio Cota node = node->left; 1238*e3feb2ccSEmilio Cota } else { 1239*e3feb2ccSEmilio Cota if (!node->right_child) { 1240*e3feb2ccSEmilio Cota return NULL; 1241*e3feb2ccSEmilio Cota } 1242*e3feb2ccSEmilio Cota 1243*e3feb2ccSEmilio Cota node = node->right; 1244*e3feb2ccSEmilio Cota } 1245*e3feb2ccSEmilio Cota } 1246*e3feb2ccSEmilio Cota } 1247*e3feb2ccSEmilio Cota 1248*e3feb2ccSEmilio Cota static QTreeNode * 1249*e3feb2ccSEmilio Cota q_tree_node_rotate_left(QTreeNode *node) 1250*e3feb2ccSEmilio Cota { 1251*e3feb2ccSEmilio Cota QTreeNode *right; 1252*e3feb2ccSEmilio Cota gint a_bal; 1253*e3feb2ccSEmilio Cota gint b_bal; 1254*e3feb2ccSEmilio Cota 1255*e3feb2ccSEmilio Cota right = node->right; 1256*e3feb2ccSEmilio Cota 1257*e3feb2ccSEmilio Cota if (right->left_child) { 1258*e3feb2ccSEmilio Cota node->right = right->left; 1259*e3feb2ccSEmilio Cota } else { 1260*e3feb2ccSEmilio Cota node->right_child = FALSE; 1261*e3feb2ccSEmilio Cota right->left_child = TRUE; 1262*e3feb2ccSEmilio Cota } 1263*e3feb2ccSEmilio Cota right->left = node; 1264*e3feb2ccSEmilio Cota 1265*e3feb2ccSEmilio Cota a_bal = node->balance; 1266*e3feb2ccSEmilio Cota b_bal = right->balance; 1267*e3feb2ccSEmilio Cota 1268*e3feb2ccSEmilio Cota if (b_bal <= 0) { 1269*e3feb2ccSEmilio Cota if (a_bal >= 1) { 1270*e3feb2ccSEmilio Cota right->balance = b_bal - 1; 1271*e3feb2ccSEmilio Cota } else { 1272*e3feb2ccSEmilio Cota right->balance = a_bal + b_bal - 2; 1273*e3feb2ccSEmilio Cota } 1274*e3feb2ccSEmilio Cota node->balance = a_bal - 1; 1275*e3feb2ccSEmilio Cota } else { 1276*e3feb2ccSEmilio Cota if (a_bal <= b_bal) { 1277*e3feb2ccSEmilio Cota right->balance = a_bal - 2; 1278*e3feb2ccSEmilio Cota } else { 1279*e3feb2ccSEmilio Cota right->balance = b_bal - 1; 1280*e3feb2ccSEmilio Cota } 1281*e3feb2ccSEmilio Cota node->balance = a_bal - b_bal - 1; 1282*e3feb2ccSEmilio Cota } 1283*e3feb2ccSEmilio Cota 1284*e3feb2ccSEmilio Cota return right; 1285*e3feb2ccSEmilio Cota } 1286*e3feb2ccSEmilio Cota 1287*e3feb2ccSEmilio Cota static QTreeNode * 1288*e3feb2ccSEmilio Cota q_tree_node_rotate_right(QTreeNode *node) 1289*e3feb2ccSEmilio Cota { 1290*e3feb2ccSEmilio Cota QTreeNode *left; 1291*e3feb2ccSEmilio Cota gint a_bal; 1292*e3feb2ccSEmilio Cota gint b_bal; 1293*e3feb2ccSEmilio Cota 1294*e3feb2ccSEmilio Cota left = node->left; 1295*e3feb2ccSEmilio Cota 1296*e3feb2ccSEmilio Cota if (left->right_child) { 1297*e3feb2ccSEmilio Cota node->left = left->right; 1298*e3feb2ccSEmilio Cota } else { 1299*e3feb2ccSEmilio Cota node->left_child = FALSE; 1300*e3feb2ccSEmilio Cota left->right_child = TRUE; 1301*e3feb2ccSEmilio Cota } 1302*e3feb2ccSEmilio Cota left->right = node; 1303*e3feb2ccSEmilio Cota 1304*e3feb2ccSEmilio Cota a_bal = node->balance; 1305*e3feb2ccSEmilio Cota b_bal = left->balance; 1306*e3feb2ccSEmilio Cota 1307*e3feb2ccSEmilio Cota if (b_bal <= 0) { 1308*e3feb2ccSEmilio Cota if (b_bal > a_bal) { 1309*e3feb2ccSEmilio Cota left->balance = b_bal + 1; 1310*e3feb2ccSEmilio Cota } else { 1311*e3feb2ccSEmilio Cota left->balance = a_bal + 2; 1312*e3feb2ccSEmilio Cota } 1313*e3feb2ccSEmilio Cota node->balance = a_bal - b_bal + 1; 1314*e3feb2ccSEmilio Cota } else { 1315*e3feb2ccSEmilio Cota if (a_bal <= -1) { 1316*e3feb2ccSEmilio Cota left->balance = b_bal + 1; 1317*e3feb2ccSEmilio Cota } else { 1318*e3feb2ccSEmilio Cota left->balance = a_bal + b_bal + 2; 1319*e3feb2ccSEmilio Cota } 1320*e3feb2ccSEmilio Cota node->balance = a_bal + 1; 1321*e3feb2ccSEmilio Cota } 1322*e3feb2ccSEmilio Cota 1323*e3feb2ccSEmilio Cota return left; 1324*e3feb2ccSEmilio Cota } 1325*e3feb2ccSEmilio Cota 1326*e3feb2ccSEmilio Cota #ifdef Q_TREE_DEBUG 1327*e3feb2ccSEmilio Cota static gint 1328*e3feb2ccSEmilio Cota q_tree_node_height(QTreeNode *node) 1329*e3feb2ccSEmilio Cota { 1330*e3feb2ccSEmilio Cota gint left_height; 1331*e3feb2ccSEmilio Cota gint right_height; 1332*e3feb2ccSEmilio Cota 1333*e3feb2ccSEmilio Cota if (node) { 1334*e3feb2ccSEmilio Cota left_height = 0; 1335*e3feb2ccSEmilio Cota right_height = 0; 1336*e3feb2ccSEmilio Cota 1337*e3feb2ccSEmilio Cota if (node->left_child) { 1338*e3feb2ccSEmilio Cota left_height = q_tree_node_height(node->left); 1339*e3feb2ccSEmilio Cota } 1340*e3feb2ccSEmilio Cota 1341*e3feb2ccSEmilio Cota if (node->right_child) { 1342*e3feb2ccSEmilio Cota right_height = q_tree_node_height(node->right); 1343*e3feb2ccSEmilio Cota } 1344*e3feb2ccSEmilio Cota 1345*e3feb2ccSEmilio Cota return MAX(left_height, right_height) + 1; 1346*e3feb2ccSEmilio Cota } 1347*e3feb2ccSEmilio Cota 1348*e3feb2ccSEmilio Cota return 0; 1349*e3feb2ccSEmilio Cota } 1350*e3feb2ccSEmilio Cota 1351*e3feb2ccSEmilio Cota static void q_tree_node_check(QTreeNode *node) 1352*e3feb2ccSEmilio Cota { 1353*e3feb2ccSEmilio Cota gint left_height; 1354*e3feb2ccSEmilio Cota gint right_height; 1355*e3feb2ccSEmilio Cota gint balance; 1356*e3feb2ccSEmilio Cota QTreeNode *tmp; 1357*e3feb2ccSEmilio Cota 1358*e3feb2ccSEmilio Cota if (node) { 1359*e3feb2ccSEmilio Cota if (node->left_child) { 1360*e3feb2ccSEmilio Cota tmp = q_tree_node_previous(node); 1361*e3feb2ccSEmilio Cota g_assert(tmp->right == node); 1362*e3feb2ccSEmilio Cota } 1363*e3feb2ccSEmilio Cota 1364*e3feb2ccSEmilio Cota if (node->right_child) { 1365*e3feb2ccSEmilio Cota tmp = q_tree_node_next(node); 1366*e3feb2ccSEmilio Cota g_assert(tmp->left == node); 1367*e3feb2ccSEmilio Cota } 1368*e3feb2ccSEmilio Cota 1369*e3feb2ccSEmilio Cota left_height = 0; 1370*e3feb2ccSEmilio Cota right_height = 0; 1371*e3feb2ccSEmilio Cota 1372*e3feb2ccSEmilio Cota if (node->left_child) { 1373*e3feb2ccSEmilio Cota left_height = q_tree_node_height(node->left); 1374*e3feb2ccSEmilio Cota } 1375*e3feb2ccSEmilio Cota if (node->right_child) { 1376*e3feb2ccSEmilio Cota right_height = q_tree_node_height(node->right); 1377*e3feb2ccSEmilio Cota } 1378*e3feb2ccSEmilio Cota 1379*e3feb2ccSEmilio Cota balance = right_height - left_height; 1380*e3feb2ccSEmilio Cota g_assert(balance == node->balance); 1381*e3feb2ccSEmilio Cota 1382*e3feb2ccSEmilio Cota if (node->left_child) { 1383*e3feb2ccSEmilio Cota q_tree_node_check(node->left); 1384*e3feb2ccSEmilio Cota } 1385*e3feb2ccSEmilio Cota if (node->right_child) { 1386*e3feb2ccSEmilio Cota q_tree_node_check(node->right); 1387*e3feb2ccSEmilio Cota } 1388*e3feb2ccSEmilio Cota } 1389*e3feb2ccSEmilio Cota } 1390*e3feb2ccSEmilio Cota #endif 1391