1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390 |
- /*
- * GLIB - Library of useful routines for C programming
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * SPDX-License-Identifier: LGPL-2.1-or-later
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
- /*
- * Modified by the GLib Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GLib Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GLib at ftp://ftp.gtk.org/pub/gtk/.
- */
- /*
- * MT safe
- */
- #include "qemu/osdep.h"
- #include "qemu/qtree.h"
- /**
- * SECTION:trees-binary
- * @title: Balanced Binary Trees
- * @short_description: a sorted collection of key/value pairs optimized
- * for searching and traversing in order
- *
- * The #QTree structure and its associated functions provide a sorted
- * collection of key/value pairs optimized for searching and traversing
- * in order. This means that most of the operations (access, search,
- * insertion, deletion, ...) on #QTree are O(log(n)) in average and O(n)
- * in worst case for time complexity. But, note that maintaining a
- * balanced sorted #QTree of n elements is done in time O(n log(n)).
- *
- * To create a new #QTree use q_tree_new().
- *
- * To insert a key/value pair into a #QTree use q_tree_insert()
- * (O(n log(n))).
- *
- * To remove a key/value pair use q_tree_remove() (O(n log(n))).
- *
- * To look up the value corresponding to a given key, use
- * q_tree_lookup() and q_tree_lookup_extended().
- *
- * To find out the number of nodes in a #QTree, use q_tree_nnodes(). To
- * get the height of a #QTree, use q_tree_height().
- *
- * To traverse a #QTree, calling a function for each node visited in
- * the traversal, use q_tree_foreach().
- *
- * To destroy a #QTree, use q_tree_destroy().
- **/
- #define MAX_GTREE_HEIGHT 40
- /**
- * QTree:
- *
- * The QTree struct is an opaque data structure representing a
- * [balanced binary tree][glib-Balanced-Binary-Trees]. It should be
- * accessed only by using the following functions.
- */
- struct _QTree {
- QTreeNode *root;
- GCompareDataFunc key_compare;
- GDestroyNotify key_destroy_func;
- GDestroyNotify value_destroy_func;
- gpointer key_compare_data;
- guint nnodes;
- gint ref_count;
- };
- struct _QTreeNode {
- gpointer key; /* key for this node */
- gpointer value; /* value stored at this node */
- QTreeNode *left; /* left subtree */
- QTreeNode *right; /* right subtree */
- gint8 balance; /* height (right) - height (left) */
- guint8 left_child;
- guint8 right_child;
- };
- static QTreeNode *q_tree_node_new(gpointer key,
- gpointer value);
- static QTreeNode *q_tree_insert_internal(QTree *tree,
- gpointer key,
- gpointer value,
- gboolean replace);
- static gboolean q_tree_remove_internal(QTree *tree,
- gconstpointer key,
- gboolean steal);
- static QTreeNode *q_tree_node_balance(QTreeNode *node);
- static QTreeNode *q_tree_find_node(QTree *tree,
- gconstpointer key);
- static QTreeNode *q_tree_node_search(QTreeNode *node,
- GCompareFunc search_func,
- gconstpointer data);
- static QTreeNode *q_tree_node_rotate_left(QTreeNode *node);
- static QTreeNode *q_tree_node_rotate_right(QTreeNode *node);
- #ifdef Q_TREE_DEBUG
- static void q_tree_node_check(QTreeNode *node);
- #endif
- static QTreeNode*
- q_tree_node_new(gpointer key,
- gpointer value)
- {
- QTreeNode *node = g_new(QTreeNode, 1);
- node->balance = 0;
- node->left = NULL;
- node->right = NULL;
- node->left_child = FALSE;
- node->right_child = FALSE;
- node->key = key;
- node->value = value;
- return node;
- }
- /**
- * q_tree_new:
- * @key_compare_func: the function used to order the nodes in the #QTree.
- * It should return values similar to the standard strcmp() function -
- * 0 if the two arguments are equal, a negative value if the first argument
- * comes before the second, or a positive value if the first argument comes
- * after the second.
- *
- * Creates a new #QTree.
- *
- * Returns: a newly allocated #QTree
- */
- QTree *
- q_tree_new(GCompareFunc key_compare_func)
- {
- g_return_val_if_fail(key_compare_func != NULL, NULL);
- return q_tree_new_full((GCompareDataFunc) key_compare_func, NULL,
- NULL, NULL);
- }
- /**
- * q_tree_new_with_data:
- * @key_compare_func: qsort()-style comparison function
- * @key_compare_data: data to pass to comparison function
- *
- * Creates a new #QTree with a comparison function that accepts user data.
- * See q_tree_new() for more details.
- *
- * Returns: a newly allocated #QTree
- */
- QTree *
- q_tree_new_with_data(GCompareDataFunc key_compare_func,
- gpointer key_compare_data)
- {
- g_return_val_if_fail(key_compare_func != NULL, NULL);
- return q_tree_new_full(key_compare_func, key_compare_data,
- NULL, NULL);
- }
- /**
- * q_tree_new_full:
- * @key_compare_func: qsort()-style comparison function
- * @key_compare_data: data to pass to comparison function
- * @key_destroy_func: a function to free the memory allocated for the key
- * used when removing the entry from the #QTree or %NULL if you don't
- * want to supply such a function
- * @value_destroy_func: a function to free the memory allocated for the
- * value used when removing the entry from the #QTree or %NULL if you
- * don't want to supply such a function
- *
- * Creates a new #QTree like q_tree_new() and allows to specify functions
- * to free the memory allocated for the key and value that get called when
- * removing the entry from the #QTree.
- *
- * Returns: a newly allocated #QTree
- */
- QTree *
- q_tree_new_full(GCompareDataFunc key_compare_func,
- gpointer key_compare_data,
- GDestroyNotify key_destroy_func,
- GDestroyNotify value_destroy_func)
- {
- QTree *tree;
- g_return_val_if_fail(key_compare_func != NULL, NULL);
- tree = g_new(QTree, 1);
- tree->root = NULL;
- tree->key_compare = key_compare_func;
- tree->key_destroy_func = key_destroy_func;
- tree->value_destroy_func = value_destroy_func;
- tree->key_compare_data = key_compare_data;
- tree->nnodes = 0;
- tree->ref_count = 1;
- return tree;
- }
- /**
- * q_tree_node_first:
- * @tree: a #QTree
- *
- * Returns the first in-order node of the tree, or %NULL
- * for an empty tree.
- *
- * Returns: (nullable) (transfer none): the first node in the tree
- *
- * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static QTreeNode *
- q_tree_node_first(QTree *tree)
- {
- QTreeNode *tmp;
- g_return_val_if_fail(tree != NULL, NULL);
- if (!tree->root) {
- return NULL;
- }
- tmp = tree->root;
- while (tmp->left_child) {
- tmp = tmp->left;
- }
- return tmp;
- }
- /**
- * q_tree_node_previous
- * @node: a #QTree node
- *
- * Returns the previous in-order node of the tree, or %NULL
- * if the passed node was already the first one.
- *
- * Returns: (nullable) (transfer none): the previous node in the tree
- *
- * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static QTreeNode *
- q_tree_node_previous(QTreeNode *node)
- {
- QTreeNode *tmp;
- g_return_val_if_fail(node != NULL, NULL);
- tmp = node->left;
- if (node->left_child) {
- while (tmp->right_child) {
- tmp = tmp->right;
- }
- }
- return tmp;
- }
- /**
- * q_tree_node_next
- * @node: a #QTree node
- *
- * Returns the next in-order node of the tree, or %NULL
- * if the passed node was already the last one.
- *
- * Returns: (nullable) (transfer none): the next node in the tree
- *
- * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static QTreeNode *
- q_tree_node_next(QTreeNode *node)
- {
- QTreeNode *tmp;
- g_return_val_if_fail(node != NULL, NULL);
- tmp = node->right;
- if (node->right_child) {
- while (tmp->left_child) {
- tmp = tmp->left;
- }
- }
- return tmp;
- }
- /**
- * q_tree_remove_all:
- * @tree: a #QTree
- *
- * Removes all nodes from a #QTree and destroys their keys and values,
- * then resets the #QTree’s root to %NULL.
- *
- * Since: 2.70 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static void QEMU_DISABLE_CFI
- q_tree_remove_all(QTree *tree)
- {
- QTreeNode *node;
- QTreeNode *next;
- g_return_if_fail(tree != NULL);
- node = q_tree_node_first(tree);
- while (node) {
- next = q_tree_node_next(node);
- if (tree->key_destroy_func) {
- tree->key_destroy_func(node->key);
- }
- if (tree->value_destroy_func) {
- tree->value_destroy_func(node->value);
- }
- g_free(node);
- #ifdef Q_TREE_DEBUG
- g_assert(tree->nnodes > 0);
- tree->nnodes--;
- #endif
- node = next;
- }
- #ifdef Q_TREE_DEBUG
- g_assert(tree->nnodes == 0);
- #endif
- tree->root = NULL;
- #ifndef Q_TREE_DEBUG
- tree->nnodes = 0;
- #endif
- }
- /**
- * q_tree_ref:
- * @tree: a #QTree
- *
- * Increments the reference count of @tree by one.
- *
- * It is safe to call this function from any thread.
- *
- * Returns: the passed in #QTree
- *
- * Since: 2.22
- */
- QTree *
- q_tree_ref(QTree *tree)
- {
- g_return_val_if_fail(tree != NULL, NULL);
- g_atomic_int_inc(&tree->ref_count);
- return tree;
- }
- /**
- * q_tree_unref:
- * @tree: a #QTree
- *
- * Decrements the reference count of @tree by one.
- * If the reference count drops to 0, all keys and values will
- * be destroyed (if destroy functions were specified) and all
- * memory allocated by @tree will be released.
- *
- * It is safe to call this function from any thread.
- *
- * Since: 2.22
- */
- void
- q_tree_unref(QTree *tree)
- {
- g_return_if_fail(tree != NULL);
- if (g_atomic_int_dec_and_test(&tree->ref_count)) {
- q_tree_remove_all(tree);
- g_free(tree);
- }
- }
- /**
- * q_tree_destroy:
- * @tree: a #QTree
- *
- * Removes all keys and values from the #QTree and decreases its
- * reference count by one. If keys and/or values are dynamically
- * allocated, you should either free them first or create the #QTree
- * using q_tree_new_full(). In the latter case the destroy functions
- * you supplied will be called on all keys and values before destroying
- * the #QTree.
- */
- void
- q_tree_destroy(QTree *tree)
- {
- g_return_if_fail(tree != NULL);
- q_tree_remove_all(tree);
- q_tree_unref(tree);
- }
- /**
- * q_tree_insert_node:
- * @tree: a #QTree
- * @key: the key to insert
- * @value: the value corresponding to the key
- *
- * Inserts a key/value pair into a #QTree.
- *
- * If the given key already exists in the #QTree its corresponding value
- * is set to the new value. If you supplied a @value_destroy_func when
- * creating the #QTree, the old value is freed using that function. If
- * you supplied a @key_destroy_func when creating the #QTree, the passed
- * key is freed using that function.
- *
- * The tree is automatically 'balanced' as new key/value pairs are added,
- * so that the distance from the root to every leaf is as small as possible.
- * The cost of maintaining a balanced tree while inserting new key/value
- * result in a O(n log(n)) operation where most of the other operations
- * are O(log(n)).
- *
- * Returns: (transfer none): the inserted (or set) node.
- *
- * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static QTreeNode *
- q_tree_insert_node(QTree *tree,
- gpointer key,
- gpointer value)
- {
- QTreeNode *node;
- g_return_val_if_fail(tree != NULL, NULL);
- node = q_tree_insert_internal(tree, key, value, FALSE);
- #ifdef Q_TREE_DEBUG
- q_tree_node_check(tree->root);
- #endif
- return node;
- }
- /**
- * q_tree_insert:
- * @tree: a #QTree
- * @key: the key to insert
- * @value: the value corresponding to the key
- *
- * Inserts a key/value pair into a #QTree.
- *
- * Inserts a new key and value into a #QTree as q_tree_insert_node() does,
- * only this function does not return the inserted or set node.
- */
- void
- q_tree_insert(QTree *tree,
- gpointer key,
- gpointer value)
- {
- q_tree_insert_node(tree, key, value);
- }
- /**
- * q_tree_replace_node:
- * @tree: a #QTree
- * @key: the key to insert
- * @value: the value corresponding to the key
- *
- * Inserts a new key and value into a #QTree similar to q_tree_insert_node().
- * The difference is that if the key already exists in the #QTree, it gets
- * replaced by the new key. If you supplied a @value_destroy_func when
- * creating the #QTree, the old value is freed using that function. If you
- * supplied a @key_destroy_func when creating the #QTree, the old key is
- * freed using that function.
- *
- * The tree is automatically 'balanced' as new key/value pairs are added,
- * so that the distance from the root to every leaf is as small as possible.
- *
- * Returns: (transfer none): the inserted (or set) node.
- *
- * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static QTreeNode *
- q_tree_replace_node(QTree *tree,
- gpointer key,
- gpointer value)
- {
- QTreeNode *node;
- g_return_val_if_fail(tree != NULL, NULL);
- node = q_tree_insert_internal(tree, key, value, TRUE);
- #ifdef Q_TREE_DEBUG
- q_tree_node_check(tree->root);
- #endif
- return node;
- }
- /**
- * q_tree_replace:
- * @tree: a #QTree
- * @key: the key to insert
- * @value: the value corresponding to the key
- *
- * Inserts a new key and value into a #QTree as q_tree_replace_node() does,
- * only this function does not return the inserted or set node.
- */
- void
- q_tree_replace(QTree *tree,
- gpointer key,
- gpointer value)
- {
- q_tree_replace_node(tree, key, value);
- }
- /* internal insert routine */
- static QTreeNode * QEMU_DISABLE_CFI
- q_tree_insert_internal(QTree *tree,
- gpointer key,
- gpointer value,
- gboolean replace)
- {
- QTreeNode *node, *retnode;
- QTreeNode *path[MAX_GTREE_HEIGHT];
- int idx;
- g_return_val_if_fail(tree != NULL, NULL);
- if (!tree->root) {
- tree->root = q_tree_node_new(key, value);
- tree->nnodes++;
- return tree->root;
- }
- idx = 0;
- path[idx++] = NULL;
- node = tree->root;
- while (1) {
- int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
- if (cmp == 0) {
- if (tree->value_destroy_func) {
- tree->value_destroy_func(node->value);
- }
- node->value = value;
- if (replace) {
- if (tree->key_destroy_func) {
- tree->key_destroy_func(node->key);
- }
- node->key = key;
- } else {
- /* free the passed key */
- if (tree->key_destroy_func) {
- tree->key_destroy_func(key);
- }
- }
- return node;
- } else if (cmp < 0) {
- if (node->left_child) {
- path[idx++] = node;
- node = node->left;
- } else {
- QTreeNode *child = q_tree_node_new(key, value);
- child->left = node->left;
- child->right = node;
- node->left = child;
- node->left_child = TRUE;
- node->balance -= 1;
- tree->nnodes++;
- retnode = child;
- break;
- }
- } else {
- if (node->right_child) {
- path[idx++] = node;
- node = node->right;
- } else {
- QTreeNode *child = q_tree_node_new(key, value);
- child->right = node->right;
- child->left = node;
- node->right = child;
- node->right_child = TRUE;
- node->balance += 1;
- tree->nnodes++;
- retnode = child;
- break;
- }
- }
- }
- /*
- * Restore balance. This is the goodness of a non-recursive
- * implementation, when we are done with balancing we 'break'
- * the loop and we are done.
- */
- while (1) {
- QTreeNode *bparent = path[--idx];
- gboolean left_node = (bparent && node == bparent->left);
- g_assert(!bparent || bparent->left == node || bparent->right == node);
- if (node->balance < -1 || node->balance > 1) {
- node = q_tree_node_balance(node);
- if (bparent == NULL) {
- tree->root = node;
- } else if (left_node) {
- bparent->left = node;
- } else {
- bparent->right = node;
- }
- }
- if (node->balance == 0 || bparent == NULL) {
- break;
- }
- if (left_node) {
- bparent->balance -= 1;
- } else {
- bparent->balance += 1;
- }
- node = bparent;
- }
- return retnode;
- }
- /**
- * q_tree_remove:
- * @tree: a #QTree
- * @key: the key to remove
- *
- * Removes a key/value pair from a #QTree.
- *
- * If the #QTree was created using q_tree_new_full(), the key and value
- * are freed using the supplied destroy functions, otherwise you have to
- * make sure that any dynamically allocated values are freed yourself.
- * If the key does not exist in the #QTree, the function does nothing.
- *
- * The cost of maintaining a balanced tree while removing a key/value
- * result in a O(n log(n)) operation where most of the other operations
- * are O(log(n)).
- *
- * Returns: %TRUE if the key was found (prior to 2.8, this function
- * returned nothing)
- */
- gboolean
- q_tree_remove(QTree *tree,
- gconstpointer key)
- {
- gboolean removed;
- g_return_val_if_fail(tree != NULL, FALSE);
- removed = q_tree_remove_internal(tree, key, FALSE);
- #ifdef Q_TREE_DEBUG
- q_tree_node_check(tree->root);
- #endif
- return removed;
- }
- /**
- * q_tree_steal:
- * @tree: a #QTree
- * @key: the key to remove
- *
- * Removes a key and its associated value from a #QTree without calling
- * the key and value destroy functions.
- *
- * If the key does not exist in the #QTree, the function does nothing.
- *
- * Returns: %TRUE if the key was found (prior to 2.8, this function
- * returned nothing)
- */
- gboolean
- q_tree_steal(QTree *tree,
- gconstpointer key)
- {
- gboolean removed;
- g_return_val_if_fail(tree != NULL, FALSE);
- removed = q_tree_remove_internal(tree, key, TRUE);
- #ifdef Q_TREE_DEBUG
- q_tree_node_check(tree->root);
- #endif
- return removed;
- }
- /* internal remove routine */
- static gboolean QEMU_DISABLE_CFI
- q_tree_remove_internal(QTree *tree,
- gconstpointer key,
- gboolean steal)
- {
- QTreeNode *node, *parent, *balance;
- QTreeNode *path[MAX_GTREE_HEIGHT];
- int idx;
- gboolean left_node;
- g_return_val_if_fail(tree != NULL, FALSE);
- if (!tree->root) {
- return FALSE;
- }
- idx = 0;
- path[idx++] = NULL;
- node = tree->root;
- while (1) {
- int cmp = tree->key_compare(key, node->key, tree->key_compare_data);
- if (cmp == 0) {
- break;
- } else if (cmp < 0) {
- if (!node->left_child) {
- return FALSE;
- }
- path[idx++] = node;
- node = node->left;
- } else {
- if (!node->right_child) {
- return FALSE;
- }
- path[idx++] = node;
- node = node->right;
- }
- }
- /*
- * The following code is almost equal to q_tree_remove_node,
- * except that we do not have to call q_tree_node_parent.
- */
- balance = parent = path[--idx];
- g_assert(!parent || parent->left == node || parent->right == node);
- left_node = (parent && node == parent->left);
- if (!node->left_child) {
- if (!node->right_child) {
- if (!parent) {
- tree->root = NULL;
- } else if (left_node) {
- parent->left_child = FALSE;
- parent->left = node->left;
- parent->balance += 1;
- } else {
- parent->right_child = FALSE;
- parent->right = node->right;
- parent->balance -= 1;
- }
- } else {
- /* node has a right child */
- QTreeNode *tmp = q_tree_node_next(node);
- tmp->left = node->left;
- if (!parent) {
- tree->root = node->right;
- } else if (left_node) {
- parent->left = node->right;
- parent->balance += 1;
- } else {
- parent->right = node->right;
- parent->balance -= 1;
- }
- }
- } else {
- /* node has a left child */
- if (!node->right_child) {
- QTreeNode *tmp = q_tree_node_previous(node);
- tmp->right = node->right;
- if (parent == NULL) {
- tree->root = node->left;
- } else if (left_node) {
- parent->left = node->left;
- parent->balance += 1;
- } else {
- parent->right = node->left;
- parent->balance -= 1;
- }
- } else {
- /* node has a both children (pant, pant!) */
- QTreeNode *prev = node->left;
- QTreeNode *next = node->right;
- QTreeNode *nextp = node;
- int old_idx = idx + 1;
- idx++;
- /* path[idx] == parent */
- /* find the immediately next node (and its parent) */
- while (next->left_child) {
- path[++idx] = nextp = next;
- next = next->left;
- }
- path[old_idx] = next;
- balance = path[idx];
- /* remove 'next' from the tree */
- if (nextp != node) {
- if (next->right_child) {
- nextp->left = next->right;
- } else {
- nextp->left_child = FALSE;
- }
- nextp->balance += 1;
- next->right_child = TRUE;
- next->right = node->right;
- } else {
- node->balance -= 1;
- }
- /* set the prev to point to the right place */
- while (prev->right_child) {
- prev = prev->right;
- }
- prev->right = next;
- /* prepare 'next' to replace 'node' */
- next->left_child = TRUE;
- next->left = node->left;
- next->balance = node->balance;
- if (!parent) {
- tree->root = next;
- } else if (left_node) {
- parent->left = next;
- } else {
- parent->right = next;
- }
- }
- }
- /* restore balance */
- if (balance) {
- while (1) {
- QTreeNode *bparent = path[--idx];
- g_assert(!bparent ||
- bparent->left == balance ||
- bparent->right == balance);
- left_node = (bparent && balance == bparent->left);
- if (balance->balance < -1 || balance->balance > 1) {
- balance = q_tree_node_balance(balance);
- if (!bparent) {
- tree->root = balance;
- } else if (left_node) {
- bparent->left = balance;
- } else {
- bparent->right = balance;
- }
- }
- if (balance->balance != 0 || !bparent) {
- break;
- }
- if (left_node) {
- bparent->balance += 1;
- } else {
- bparent->balance -= 1;
- }
- balance = bparent;
- }
- }
- if (!steal) {
- if (tree->key_destroy_func) {
- tree->key_destroy_func(node->key);
- }
- if (tree->value_destroy_func) {
- tree->value_destroy_func(node->value);
- }
- }
- g_free(node);
- tree->nnodes--;
- return TRUE;
- }
- /**
- * q_tree_lookup_node:
- * @tree: a #QTree
- * @key: the key to look up
- *
- * Gets the tree node corresponding to the given key. Since a #QTree is
- * automatically balanced as key/value pairs are added, key lookup
- * is O(log n) (where n is the number of key/value pairs in the tree).
- *
- * Returns: (nullable) (transfer none): the tree node corresponding to
- * the key, or %NULL if the key was not found
- *
- * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static QTreeNode *
- q_tree_lookup_node(QTree *tree,
- gconstpointer key)
- {
- g_return_val_if_fail(tree != NULL, NULL);
- return q_tree_find_node(tree, key);
- }
- /**
- * q_tree_lookup:
- * @tree: a #QTree
- * @key: the key to look up
- *
- * Gets the value corresponding to the given key. Since a #QTree is
- * automatically balanced as key/value pairs are added, key lookup
- * is O(log n) (where n is the number of key/value pairs in the tree).
- *
- * Returns: the value corresponding to the key, or %NULL
- * if the key was not found
- */
- gpointer
- q_tree_lookup(QTree *tree,
- gconstpointer key)
- {
- QTreeNode *node;
- node = q_tree_lookup_node(tree, key);
- return node ? node->value : NULL;
- }
- /**
- * q_tree_lookup_extended:
- * @tree: a #QTree
- * @lookup_key: the key to look up
- * @orig_key: (out) (optional) (nullable): returns the original key
- * @value: (out) (optional) (nullable): returns the value associated with
- * the key
- *
- * Looks up a key in the #QTree, returning the original key and the
- * associated value. This is useful if you need to free the memory
- * allocated for the original key, for example before calling
- * q_tree_remove().
- *
- * Returns: %TRUE if the key was found in the #QTree
- */
- gboolean
- q_tree_lookup_extended(QTree *tree,
- gconstpointer lookup_key,
- gpointer *orig_key,
- gpointer *value)
- {
- QTreeNode *node;
- g_return_val_if_fail(tree != NULL, FALSE);
- node = q_tree_find_node(tree, lookup_key);
- if (node) {
- if (orig_key) {
- *orig_key = node->key;
- }
- if (value) {
- *value = node->value;
- }
- return TRUE;
- } else {
- return FALSE;
- }
- }
- /**
- * q_tree_foreach:
- * @tree: a #QTree
- * @func: the function to call for each node visited.
- * If this function returns %TRUE, the traversal is stopped.
- * @user_data: user data to pass to the function
- *
- * Calls the given function for each of the key/value pairs in the #QTree.
- * The function is passed the key and value of each pair, and the given
- * @data parameter. The tree is traversed in sorted order.
- *
- * The tree may not be modified while iterating over it (you can't
- * add/remove items). To remove all items matching a predicate, you need
- * to add each item to a list in your #GTraverseFunc as you walk over
- * the tree, then walk the list and remove each item.
- */
- void
- q_tree_foreach(QTree *tree,
- GTraverseFunc func,
- gpointer user_data)
- {
- QTreeNode *node;
- g_return_if_fail(tree != NULL);
- if (!tree->root) {
- return;
- }
- node = q_tree_node_first(tree);
- while (node) {
- if ((*func)(node->key, node->value, user_data)) {
- break;
- }
- node = q_tree_node_next(node);
- }
- }
- /**
- * q_tree_search_node:
- * @tree: a #QTree
- * @search_func: a function used to search the #QTree
- * @user_data: the data passed as the second argument to @search_func
- *
- * Searches a #QTree using @search_func.
- *
- * The @search_func is called with a pointer to the key of a key/value
- * pair in the tree, and the passed in @user_data. If @search_func returns
- * 0 for a key/value pair, then the corresponding node is returned as
- * the result of q_tree_search(). If @search_func returns -1, searching
- * will proceed among the key/value pairs that have a smaller key; if
- * @search_func returns 1, searching will proceed among the key/value
- * pairs that have a larger key.
- *
- * Returns: (nullable) (transfer none): the node corresponding to the
- * found key, or %NULL if the key was not found
- *
- * Since: 2.68 in GLib. Internal in Qtree, i.e. not in the public API.
- */
- static QTreeNode *
- q_tree_search_node(QTree *tree,
- GCompareFunc search_func,
- gconstpointer user_data)
- {
- g_return_val_if_fail(tree != NULL, NULL);
- if (!tree->root) {
- return NULL;
- }
- return q_tree_node_search(tree->root, search_func, user_data);
- }
- /**
- * q_tree_search:
- * @tree: a #QTree
- * @search_func: a function used to search the #QTree
- * @user_data: the data passed as the second argument to @search_func
- *
- * Searches a #QTree using @search_func.
- *
- * The @search_func is called with a pointer to the key of a key/value
- * pair in the tree, and the passed in @user_data. If @search_func returns
- * 0 for a key/value pair, then the corresponding value is returned as
- * the result of q_tree_search(). If @search_func returns -1, searching
- * will proceed among the key/value pairs that have a smaller key; if
- * @search_func returns 1, searching will proceed among the key/value
- * pairs that have a larger key.
- *
- * Returns: the value corresponding to the found key, or %NULL
- * if the key was not found
- */
- gpointer
- q_tree_search(QTree *tree,
- GCompareFunc search_func,
- gconstpointer user_data)
- {
- QTreeNode *node;
- node = q_tree_search_node(tree, search_func, user_data);
- return node ? node->value : NULL;
- }
- /**
- * q_tree_height:
- * @tree: a #QTree
- *
- * Gets the height of a #QTree.
- *
- * If the #QTree contains no nodes, the height is 0.
- * If the #QTree contains only one root node the height is 1.
- * If the root node has children the height is 2, etc.
- *
- * Returns: the height of @tree
- */
- gint
- q_tree_height(QTree *tree)
- {
- QTreeNode *node;
- gint height;
- g_return_val_if_fail(tree != NULL, 0);
- if (!tree->root) {
- return 0;
- }
- height = 0;
- node = tree->root;
- while (1) {
- height += 1 + MAX(node->balance, 0);
- if (!node->left_child) {
- return height;
- }
- node = node->left;
- }
- }
- /**
- * q_tree_nnodes:
- * @tree: a #QTree
- *
- * Gets the number of nodes in a #QTree.
- *
- * Returns: the number of nodes in @tree
- */
- gint
- q_tree_nnodes(QTree *tree)
- {
- g_return_val_if_fail(tree != NULL, 0);
- return tree->nnodes;
- }
- static QTreeNode *
- q_tree_node_balance(QTreeNode *node)
- {
- if (node->balance < -1) {
- if (node->left->balance > 0) {
- node->left = q_tree_node_rotate_left(node->left);
- }
- node = q_tree_node_rotate_right(node);
- } else if (node->balance > 1) {
- if (node->right->balance < 0) {
- node->right = q_tree_node_rotate_right(node->right);
- }
- node = q_tree_node_rotate_left(node);
- }
- return node;
- }
- static QTreeNode * QEMU_DISABLE_CFI
- q_tree_find_node(QTree *tree,
- gconstpointer key)
- {
- QTreeNode *node;
- gint cmp;
- node = tree->root;
- if (!node) {
- return NULL;
- }
- while (1) {
- cmp = tree->key_compare(key, node->key, tree->key_compare_data);
- if (cmp == 0) {
- return node;
- } else if (cmp < 0) {
- if (!node->left_child) {
- return NULL;
- }
- node = node->left;
- } else {
- if (!node->right_child) {
- return NULL;
- }
- node = node->right;
- }
- }
- }
- static QTreeNode *
- q_tree_node_search(QTreeNode *node,
- GCompareFunc search_func,
- gconstpointer data)
- {
- gint dir;
- if (!node) {
- return NULL;
- }
- while (1) {
- dir = (*search_func)(node->key, data);
- if (dir == 0) {
- return node;
- } else if (dir < 0) {
- if (!node->left_child) {
- return NULL;
- }
- node = node->left;
- } else {
- if (!node->right_child) {
- return NULL;
- }
- node = node->right;
- }
- }
- }
- static QTreeNode *
- q_tree_node_rotate_left(QTreeNode *node)
- {
- QTreeNode *right;
- gint a_bal;
- gint b_bal;
- right = node->right;
- if (right->left_child) {
- node->right = right->left;
- } else {
- node->right_child = FALSE;
- right->left_child = TRUE;
- }
- right->left = node;
- a_bal = node->balance;
- b_bal = right->balance;
- if (b_bal <= 0) {
- if (a_bal >= 1) {
- right->balance = b_bal - 1;
- } else {
- right->balance = a_bal + b_bal - 2;
- }
- node->balance = a_bal - 1;
- } else {
- if (a_bal <= b_bal) {
- right->balance = a_bal - 2;
- } else {
- right->balance = b_bal - 1;
- }
- node->balance = a_bal - b_bal - 1;
- }
- return right;
- }
- static QTreeNode *
- q_tree_node_rotate_right(QTreeNode *node)
- {
- QTreeNode *left;
- gint a_bal;
- gint b_bal;
- left = node->left;
- if (left->right_child) {
- node->left = left->right;
- } else {
- node->left_child = FALSE;
- left->right_child = TRUE;
- }
- left->right = node;
- a_bal = node->balance;
- b_bal = left->balance;
- if (b_bal <= 0) {
- if (b_bal > a_bal) {
- left->balance = b_bal + 1;
- } else {
- left->balance = a_bal + 2;
- }
- node->balance = a_bal - b_bal + 1;
- } else {
- if (a_bal <= -1) {
- left->balance = b_bal + 1;
- } else {
- left->balance = a_bal + b_bal + 2;
- }
- node->balance = a_bal + 1;
- }
- return left;
- }
- #ifdef Q_TREE_DEBUG
- static gint
- q_tree_node_height(QTreeNode *node)
- {
- gint left_height;
- gint right_height;
- if (node) {
- left_height = 0;
- right_height = 0;
- if (node->left_child) {
- left_height = q_tree_node_height(node->left);
- }
- if (node->right_child) {
- right_height = q_tree_node_height(node->right);
- }
- return MAX(left_height, right_height) + 1;
- }
- return 0;
- }
- static void q_tree_node_check(QTreeNode *node)
- {
- gint left_height;
- gint right_height;
- gint balance;
- QTreeNode *tmp;
- if (node) {
- if (node->left_child) {
- tmp = q_tree_node_previous(node);
- g_assert(tmp->right == node);
- }
- if (node->right_child) {
- tmp = q_tree_node_next(node);
- g_assert(tmp->left == node);
- }
- left_height = 0;
- right_height = 0;
- if (node->left_child) {
- left_height = q_tree_node_height(node->left);
- }
- if (node->right_child) {
- right_height = q_tree_node_height(node->right);
- }
- balance = right_height - left_height;
- g_assert(balance == node->balance);
- if (node->left_child) {
- q_tree_node_check(node->left);
- }
- if (node->right_child) {
- q_tree_node_check(node->right);
- }
- }
- }
- #endif
|